Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

file reference counts can get corrupted #12299

Merged
merged 1 commit into from
Jul 11, 2021
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
5 changes: 3 additions & 2 deletions include/sys/fm/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ extern "C" {
#endif

#include <sys/nvpair.h>
#include <sys/zfs_file.h>

/*
* Shared user/kernel definitions for class length, error channel name,
Expand Down Expand Up @@ -95,8 +96,8 @@ extern void fm_fini(void);
extern void zfs_zevent_post_cb(nvlist_t *nvl, nvlist_t *detector);
extern int zfs_zevent_post(nvlist_t *, nvlist_t *, zevent_cb_t *);
extern void zfs_zevent_drain_all(int *);
extern int zfs_zevent_fd_hold(int, minor_t *, zfs_zevent_t **);
extern void zfs_zevent_fd_rele(int);
extern zfs_file_t *zfs_zevent_fd_hold(int, minor_t *, zfs_zevent_t **);
extern void zfs_zevent_fd_rele(zfs_file_t *);
extern int zfs_zevent_next(zfs_zevent_t *, nvlist_t **, uint64_t *, uint64_t *);
extern int zfs_zevent_wait(zfs_zevent_t *);
extern int zfs_zevent_seek(zfs_zevent_t *, uint64_t);
Expand Down
6 changes: 4 additions & 2 deletions include/sys/zfs_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#ifndef _SYS_ZFS_FILE_H
#define _SYS_ZFS_FILE_H

#include <sys/zfs_context.h>

#ifndef _KERNEL
typedef struct zfs_file {
int f_fd;
Expand Down Expand Up @@ -55,8 +57,8 @@ int zfs_file_fallocate(zfs_file_t *fp, int mode, loff_t offset, loff_t len);
loff_t zfs_file_off(zfs_file_t *fp);
int zfs_file_unlink(const char *);

int zfs_file_get(int fd, zfs_file_t **fp);
void zfs_file_put(int fd);
zfs_file_t *zfs_file_get(int fd);
void zfs_file_put(zfs_file_t *fp);
void *zfs_file_private(zfs_file_t *fp);

#endif /* _SYS_ZFS_FILE_H */
2 changes: 1 addition & 1 deletion include/sys/zfs_ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ typedef struct zfsdev_state {
} zfsdev_state_t;

extern void *zfsdev_get_state(minor_t minor, enum zfsdev_state_type which);
extern int zfsdev_getminor(int fd, minor_t *minorp);
extern int zfsdev_getminor(zfs_file_t *fp, minor_t *minorp);

extern uint_t zfs_fsyncer_key;
extern uint_t zfs_allow_log_key;
Expand Down
4 changes: 2 additions & 2 deletions include/sys/zfs_onexit.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ extern void zfs_onexit_destroy(zfs_onexit_t *zo);

#endif

extern int zfs_onexit_fd_hold(int fd, minor_t *minorp);
extern void zfs_onexit_fd_rele(int fd);
extern zfs_file_t *zfs_onexit_fd_hold(int fd, minor_t *minorp);
extern void zfs_onexit_fd_rele(zfs_file_t *);
extern int zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data,
uint64_t *action_handle);

Expand Down
20 changes: 9 additions & 11 deletions lib/libzpool/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -928,16 +928,16 @@ kmem_asprintf(const char *fmt, ...)
}

/* ARGSUSED */
int
zfs_file_t *
zfs_onexit_fd_hold(int fd, minor_t *minorp)
{
*minorp = 0;
return (0);
return (NULL);
}

/* ARGSUSED */
void
zfs_onexit_fd_rele(int fd)
zfs_onexit_fd_rele(zfs_file_t *fp)
{
}

Expand Down Expand Up @@ -1347,28 +1347,26 @@ zfs_file_unlink(const char *path)
* Get reference to file pointer
*
* fd - input file descriptor
* fpp - pointer to file pointer
*
* Returns 0 on success EBADF on failure.
* Returns pointer to file struct or NULL.
* Unsupported in user space.
*/
int
zfs_file_get(int fd, zfs_file_t **fpp)
zfs_file_t *
zfs_file_get(int fd)
{
abort();

return (EOPNOTSUPP);
return (NULL);
}

/*
* Drop reference to file pointer
*
* fd - input file descriptor
* fp - pointer to file struct
*
* Unsupported in user space.
*/
void
zfs_file_put(int fd)
zfs_file_put(zfs_file_t *fp)
{
abort();
}
Expand Down
19 changes: 6 additions & 13 deletions module/os/freebsd/zfs/zfs_file_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,28 +241,21 @@ zfs_file_fsync(zfs_file_t *fp, int flags)
return (zfs_vop_fsync(fp->f_vnode));
}

int
zfs_file_get(int fd, zfs_file_t **fpp)
zfs_file_t *
zfs_file_get(int fd)
{
struct file *fp;

if (fget(curthread, fd, &cap_no_rights, &fp))
return (SET_ERROR(EBADF));
return (NULL);

*fpp = fp;
return (0);
return (fp);
}

void
zfs_file_put(int fd)
zfs_file_put(zfs_file_t *fp)
{
struct file *fp;

/* No CAP_ rights required, as we're only releasing. */
if (fget(curthread, fd, &cap_no_rights, &fp) == 0) {
fdrop(fp, curthread);
fdrop(fp, curthread);
}
fdrop(fp, curthread);
}

loff_t
Expand Down
28 changes: 7 additions & 21 deletions module/os/linux/zfs/zfs_file_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,36 +407,22 @@ zfs_file_unlink(const char *path)
* Get reference to file pointer
*
* fd - input file descriptor
* fpp - pointer to file pointer
*
* Returns 0 on success EBADF on failure.
* Returns pointer to file struct or NULL
*/
int
zfs_file_get(int fd, zfs_file_t **fpp)
zfs_file_t *
zfs_file_get(int fd)
{
zfs_file_t *fp;

fp = fget(fd);
if (fp == NULL)
return (EBADF);

*fpp = fp;

return (0);
return (fget(fd));
}

/*
* Drop reference to file pointer
*
* fd - input file descriptor
* fp - input file struct pointer
*/
void
zfs_file_put(int fd)
zfs_file_put(zfs_file_t *fp)
{
struct file *fp;

if ((fp = fget(fd)) != NULL) {
fput(fp);
fput(fp);
}
fput(fp);
}
20 changes: 12 additions & 8 deletions module/zfs/fm.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,25 +278,29 @@ zfs_zevent_minor_to_state(minor_t minor, zfs_zevent_t **ze)
return (0);
}

int
zfs_file_t *
zfs_zevent_fd_hold(int fd, minor_t *minorp, zfs_zevent_t **ze)
{
int error;
zfs_file_t *fp = zfs_file_get(fd);
if (fp == NULL)
return (NULL);

error = zfsdev_getminor(fd, minorp);
int error = zfsdev_getminor(fp, minorp);
if (error == 0)
error = zfs_zevent_minor_to_state(*minorp, ze);

if (error)
zfs_zevent_fd_rele(fd);
if (error) {
zfs_zevent_fd_rele(fp);
fp = NULL;
}

return (error);
return (fp);
}

void
zfs_zevent_fd_rele(int fd)
zfs_zevent_fd_rele(zfs_file_t *fp)
{
zfs_file_put(fd);
zfs_file_put(fp);
}

/*
Expand Down
Loading