Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 76 additions & 41 deletions fs/deepin_err_notify.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,54 +61,56 @@ int deepin_err_notify_enabled(void)
return deepin_err_notify_initialized && deepin_err_notify_enable;
}

/**
* deepin_err_notify_should_send - Check if error notification should be sent
*
* This function checks both the enable status and rate limiting to determine
* whether an error notification should be sent.
*
* Return: 1 if notification should be sent, 0 otherwise
*/
int deepin_err_notify_should_send(void)
{

/*
* Rate limiting: Allow 20 calls per 5 seconds.
* Rationale: Prevent excessive error notifications under high load,
* which could overwhelm the monitoring system or cause log flooding.
* 20 notifications per 5 seconds is sufficient to capture relevant
* filesystem errors without missing critical events.
*/
static DEFINE_RATELIMIT_STATE(deepin_err_notify_ratelimit, 5 * HZ, 20);

if (!deepin_err_notify_enabled())
return 0;

return __ratelimit(&deepin_err_notify_ratelimit);
}

static int
prepare_and_notify_fs_error(const struct deepin_path_last *path_lasts,
int path_last_count)
{
/* TODO: Implement in next commit */
Comment on lines +90 to +94
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question (bug_risk): prepare_and_notify_fs_error() currently always returns -EOPNOTSUPP, which prevents any notifications from being sent.

Since deepin_check_and_notify_ro_fs_err() now calls prepare_and_notify_fs_error(), and this always returns -EOPNOTSUPP, the new call sites effectively perform no notification (beyond potential debug logs). If this placeholder is intentional for a staged refactor, consider temporarily guarding or disabling these call sites to avoid a regression where notifications look wired up but never reach userspace.

return -EOPNOTSUPP;
}

/* Check if overlay filesystem is mounted on /usr and send read only error notification */
void deepin_check_and_notify_ro_fs_err(const struct path *path,
void deepin_check_and_notify_ro_fs_err(const struct deepin_path_last *path_last,
const char *func_name)
{
char *path_buf = NULL;
char *full_path = "";
/* Rate limiting: allow 100 calls per 5 seconds */
static DEFINE_RATELIMIT_STATE(deepin_ro_fs_err_ratelimit,
5 * HZ, /* 5 seconds interval */
100); /* 100 calls per interval */

/* Check rate limit before proceeding */
if (!__ratelimit(&deepin_ro_fs_err_ratelimit))
return;

/* Early return if path or path->mnt is invalid */
if (!path || !path->mnt || !path->mnt->mnt_sb)
return;
int ret;

/* Use filesystem callback to decide if notification should be sent.
* If filesystem implements the callback, use it.
*/
if (path->mnt->mnt_sb->s_op &&
path->mnt->mnt_sb->s_op->deepin_should_notify_error) {
if (!path->mnt->mnt_sb->s_op->deepin_should_notify_error(path->mnt->mnt_sb))
return;
} else {
/* If filesystem does not implement the callback, return immediately. */
/* Early return if path_last is invalid */
if (!path_last)
return;
}
ret = prepare_and_notify_fs_error(path_last, 1);

/* Attempt to get the full path.
* Dynamic allocation is used to avoid excessive frame size.
*/
if (path->dentry) {
path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
if (path_buf) {
char *p = NULL;

p = d_path(path, path_buf, PATH_MAX);
if (!IS_ERR(p))
full_path = p;
}
if (ret < 0) {
pr_err(
"deepin_err_notify: Failed to send notification to userspace: %d\n",
ret);
}

deepin_send_ro_fs_err_notification(full_path, func_name);

kfree(path_buf);
}

/* Define multicast group */
Expand Down Expand Up @@ -192,6 +194,22 @@ void deepin_send_ro_fs_err_notification(const char *filename,
kfree_skb(skb);
}

/**
* deepin_put_path_last - Release resources held by deepin_path_last structure
* @path_last: Pointer to the deepin_path_last structure to release
*
* This function releases the path reference and frees the allocated filename
* string in the deepin_path_last structure.
*/
void deepin_put_path_last(struct deepin_path_last *path_last)
{
if (path_last) {
path_put(&path_last->path);
kfree(path_last->last);
path_last->last = NULL;
}
}

/* sysctl table and initialization */
#ifdef CONFIG_SYSCTL
static struct ctl_table deepin_err_notify_sysctls[] = {
Expand Down Expand Up @@ -239,5 +257,22 @@ static int __init deepin_err_notify_init(void)
return 0;
}

/**
* deepin_notify_rename_ro_fs_err - Notify read-only filesystem errors during rename
* @old_last: qstr for old filename
* @new_last: qstr for new filename
* @old_path: path of old parent directory
* @new_path: path of new parent directory
*
* This function is called when a rename operation fails with EROFS error.
*/
void deepin_notify_rename_ro_fs_err(const struct qstr *old_last,
const struct qstr *new_last,
const struct path *old_path,
const struct path *new_path)
{
/* Simplified implementation - will be enhanced in next commit */
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deepin_notify_rename_ro_fs_err function is currently a stub that only logs a debug message. This means rename operations with EROFS errors will not send actual notifications to userspace until this is implemented. Consider adding a TODO comment or tracking issue reference to ensure this gets implemented, or clarify if this is intentional for this commit.

Suggested change
/* Simplified implementation - will be enhanced in next commit */
/* Simplified implementation - will be enhanced in next commit */
/* TODO: Implement userspace notification for EROFS errors during rename.
* See https://github.com/linuxdeepin/deepin-kernel/issues/123 for tracking.
*/

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

/* Use fs_initcall to ensure initialization before file system operations */
fs_initcall(deepin_err_notify_init);
25 changes: 24 additions & 1 deletion fs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,33 @@ int deepin_get_path_for_err_notify(int dfd, struct filename *name, struct path *
/*
* deepin_err_notify.c
*/
struct deepin_path_last {
struct path path;
const char *last;
};

int deepin_lookup_path_or_parent(int dfd, struct filename *name,
unsigned int flags,
struct deepin_path_last *result_path_last);

int deepin_err_notify_enabled(void);
void deepin_check_and_notify_ro_fs_err(const struct path *path, const char *func_name);
int deepin_err_notify_should_send(void);
void deepin_check_and_notify_ro_fs_err(const struct deepin_path_last *path_last,
const char *func_name);
void deepin_notify_rename_ro_fs_err(const struct qstr *old_last,
const struct qstr *new_last,
const struct path *old_path,
const struct path *new_path);
void deepin_put_path_last(struct deepin_path_last *path_last);
void deepin_send_ro_fs_err_notification(const char *filename, const char *func_name);

#ifdef CONFIG_DEEPIN_ERR_NOTIFY
#define deepin_should_notify_ro_fs_err(error) \
unlikely(((error) == -EROFS) && deepin_err_notify_should_send())
#else
#define deepin_should_notify_ro_fs_err(error) 0
#endif

/*
* namespace.c
*/
Expand Down
11 changes: 7 additions & 4 deletions fs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -903,10 +903,13 @@ SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
if (error == -ENOIOCTLCMD)
error = vfs_ioctl(f.file, cmd, arg);

#ifdef CONFIG_DEEPIN_ERR_NOTIFY
if (unlikely((error == -EROFS) && deepin_err_notify_enabled()))
deepin_check_and_notify_ro_fs_err(&f.file->f_path, "ioctl");
#endif /* CONFIG_DEEPIN_ERR_NOTIFY */
if (deepin_should_notify_ro_fs_err(error)) {
struct deepin_path_last tmp_path_last = {
.path = f.file->f_path,
.last = NULL
};
deepin_check_and_notify_ro_fs_err(&tmp_path_last, "ioctl");
}

out:
fdput(f);
Expand Down
Loading
Loading