diff --git a/patch/kernel/sun7i-default/systemd_fix_for_3.4.y.patch b/patch/kernel/sun7i-default/systemd_fix_for_3.4.y.patch new file mode 100644 index 000000000..716aa4482 --- /dev/null +++ b/patch/kernel/sun7i-default/systemd_fix_for_3.4.y.patch @@ -0,0 +1,115 @@ +From ca925a740afc0a377946d72680c40f9e7719e4ec Mon Sep 17 00:00:00 2001 +From: Zhang Ning <832666+zhangn1985@users.noreply.github.com> +Date: Sun, 27 Jan 2019 18:37:00 +0800 +Subject: [PATCH] fs/file_table: split fget_light + +due to systemd updated, sun8i kernel doesn't compact to new systemd. +after check systemd code, it return -EBADF in below code: + +https://github.com/systemd/systemd/blob/master/src/basic/fs-util.c#L804-L815 + +fstat on path fds (open with O_PATH). + +after check sun8i kernel code, in fstat path, fget_light rectly returns +NULL on path fds (file->f_mode & FMODE_PATH). + +on mainline kernel, fget_light is wraper function of __fget_light. +on fstat path, it uses __fget_light, doesn't check FMODE_PATH. + +so follow mainline kernel, change the behavior of sun8i kernel. + +test case: + +int main(int argc, char **argv) +{ + int fd; + struct stat previous_stat; + + fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH); + if (fd < 0) { + printf("%d, %s\n", __LINE__, strerror(errno)); + return -errno; + } + + if(fstat(fd, &previous_stat) < 0) { + + printf("%d, %s\n", __LINE__, strerror(errno)); + return -errno; + } +} + +expect no error. + +Signed-off-by: Zhang Ning <832666+zhangn1985@users.noreply.github.com> +--- + fs/file_table.c | 11 ++++++++--- + fs/stat.c | 2 +- + include/linux/file.h | 1 + + 3 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/fs/file_table.c b/fs/file_table.c +index a01710a6ff3b..afa758fc3764 100644 +--- a/fs/file_table.c ++++ b/fs/file_table.c +@@ -322,7 +322,7 @@ EXPORT_SYMBOL(fget_raw); + * The fput_needed flag returned by fget_light should be passed to the + * corresponding fput_light. + */ +-struct file *fget_light(unsigned int fd, int *fput_needed) ++struct file *__fget_light(unsigned int fd, fmode_t mode, int *fput_needed) + { + struct file *file; + struct files_struct *files = current->files; +@@ -330,13 +330,13 @@ struct file *fget_light(unsigned int fd, int *fput_needed) + *fput_needed = 0; + if (atomic_read(&files->count) == 1) { + file = fcheck_files(files, fd); +- if (file && (file->f_mode & FMODE_PATH)) ++ if (file && (file->f_mode & mode)) + file = NULL; + } else { + rcu_read_lock(); + file = fcheck_files(files, fd); + if (file) { +- if (!(file->f_mode & FMODE_PATH) && ++ if (!(file->f_mode & mode) && + atomic_long_inc_not_zero(&file->f_count)) + *fput_needed = 1; + else +@@ -349,6 +349,11 @@ struct file *fget_light(unsigned int fd, int *fput_needed) + return file; + } + ++struct file *fget_light(unsigned int fd, int *fput_needed) ++{ ++ return __fget_light(fd, FMODE_PATH, fput_needed); ++} ++ + struct file *fget_raw_light(unsigned int fd, int *fput_needed) + { + struct file *file; +diff --git a/fs/stat.c b/fs/stat.c +index 88b36c770762..957d3348bfc8 100644 +--- a/fs/stat.c ++++ b/fs/stat.c +@@ -58,7 +58,7 @@ EXPORT_SYMBOL(vfs_getattr); + int vfs_fstat(unsigned int fd, struct kstat *stat) + { + int fput_needed; +- struct file *f = fget_light(fd, &fput_needed); ++ struct file *f = __fget_light(fd, 0, &fput_needed); + int error = -EBADF; + + if (f) { +diff --git a/include/linux/file.h b/include/linux/file.h +index 58bf158c53d9..86fed86eeba2 100644 +--- a/include/linux/file.h ++++ b/include/linux/file.h +@@ -28,6 +28,7 @@ static inline void fput_light(struct file *file, int fput_needed) + + extern struct file *fget(unsigned int fd); + extern struct file *fget_light(unsigned int fd, int *fput_needed); ++extern struct file *__fget_light(unsigned int fd, fmode_t mode, int *fput_needed); + extern struct file *fget_raw(unsigned int fd); + extern struct file *fget_raw_light(unsigned int fd, int *fput_needed); + extern void set_close_on_exec(unsigned int fd, int flag);