svn commit: r319316 - in head/sys/compat/linuxkpi/common: include/linux src
Hans Petter Selasky
hselasky at FreeBSD.org
Wed May 31 12:03:00 UTC 2017
Author: hselasky
Date: Wed May 31 12:02:59 2017
New Revision: 319316
URL: https://svnweb.freebsd.org/changeset/base/319316
Log:
Fixes for refcounting "struct linux_file" in the LinuxKPI.
- Allow "struct linux_file" to be refcounted when its "_file" member
is NULL by using its "f_count" field. The reference counts are
transferred to the file structure when the file descriptor is
installed.
- Add missing vdrop() calls for error cases during open().
- Set the "_file" member of "struct linux_file" during open. This
allows use of refcounting through get_file() and fput() with LinuxKPI
character devices.
MFC after: 1 week
Sponsored by: Mellanox Technologies
Modified:
head/sys/compat/linuxkpi/common/include/linux/file.h
head/sys/compat/linuxkpi/common/include/linux/fs.h
head/sys/compat/linuxkpi/common/src/linux_compat.c
Modified: head/sys/compat/linuxkpi/common/include/linux/file.h
==============================================================================
--- head/sys/compat/linuxkpi/common/include/linux/file.h Wed May 31 10:32:13 2017 (r319315)
+++ head/sys/compat/linuxkpi/common/include/linux/file.h Wed May 31 12:02:59 2017 (r319316)
@@ -2,7 +2,7 @@
* Copyright (c) 2010 Isilon Systems, Inc.
* Copyright (c) 2010 iX Systems, Inc.
* Copyright (c) 2010 Panasas, Inc.
- * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -60,19 +60,24 @@ linux_fget(unsigned int fd)
return (struct linux_file *)file->f_data;
}
+extern void linux_file_free(struct linux_file *filp);
+
static inline void
fput(struct linux_file *filp)
{
- if (filp->_file == NULL) {
- kfree(filp);
- return;
+ if (refcount_release(filp->_file == NULL ?
+ &filp->f_count : &filp->_file->f_count)) {
+ linux_file_free(filp);
}
- if (refcount_release(&filp->_file->f_count)) {
- _fdrop(filp->_file, curthread);
- kfree(filp);
- }
}
+static inline unsigned int
+file_count(struct linux_file *filp)
+{
+ return (filp->_file == NULL ?
+ filp->f_count : filp->_file->f_count);
+}
+
static inline void
put_unused_fd(unsigned int fd)
{
@@ -106,6 +111,10 @@ fd_install(unsigned int fd, struct linux_file *filp)
} else {
filp->_file = file;
finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops);
+
+ /* transfer reference count from "filp" to "file" */
+ while (refcount_release(&filp->f_count) == 0)
+ refcount_acquire(&file->f_count);
}
/* drop the extra reference */
@@ -150,6 +159,8 @@ alloc_file(int mode, const struct file_operations *fop
filp = kzalloc(sizeof(*filp), GFP_KERNEL);
if (filp == NULL)
return (NULL);
+
+ filp->f_count = 1;
filp->f_op = fops;
filp->f_mode = mode;
@@ -171,7 +182,7 @@ static inline struct fd fdget(unsigned int fd)
return (struct fd){f};
}
-#define file linux_file
-#define fget linux_fget
+#define file linux_file
+#define fget(...) linux_fget(__VA_ARGS__)
#endif /* _LINUX_FILE_H_ */
Modified: head/sys/compat/linuxkpi/common/include/linux/fs.h
==============================================================================
--- head/sys/compat/linuxkpi/common/include/linux/fs.h Wed May 31 10:32:13 2017 (r319315)
+++ head/sys/compat/linuxkpi/common/include/linux/fs.h Wed May 31 12:02:59 2017 (r319316)
@@ -79,6 +79,7 @@ struct linux_file {
struct selinfo f_selinfo;
struct sigio *f_sigio;
struct vnode *f_vnode;
+ volatile u_int f_count;
};
#define file linux_file
@@ -218,6 +219,14 @@ iminor(struct inode *inode)
{
return (minor(dev2unit(inode->v_rdev)));
+}
+
+static inline struct linux_file *
+get_file(struct linux_file *f)
+{
+
+ refcount_acquire(f->_file == NULL ? &f->f_count : &f->_file->f_count);
+ return (f);
}
static inline struct inode *
Modified: head/sys/compat/linuxkpi/common/src/linux_compat.c
==============================================================================
--- head/sys/compat/linuxkpi/common/src/linux_compat.c Wed May 31 10:32:13 2017 (r319315)
+++ head/sys/compat/linuxkpi/common/src/linux_compat.c Wed May 31 12:02:59 2017 (r319316)
@@ -401,6 +401,20 @@ linux_file_dtor(void *cdp)
kfree(filp);
}
+void
+linux_file_free(struct linux_file *filp)
+{
+ if (filp->_file == NULL) {
+ kfree(filp);
+ } else {
+ /*
+ * The close method of the character device or file
+ * will free the linux_file structure:
+ */
+ _fdrop(filp->_file, curthread);
+ }
+}
+
static int
linux_cdev_pager_populate(vm_object_t vm_obj, vm_pindex_t pidx, int fault_type,
vm_prot_t max_prot, vm_pindex_t *first, vm_pindex_t *last)
@@ -593,9 +607,12 @@ linux_dev_open(struct cdev *dev, int oflags, int devty
vhold(file->f_vnode);
filp->f_vnode = file->f_vnode;
linux_set_current(td);
+ filp->_file = file;
+
if (filp->f_op->open) {
error = -filp->f_op->open(file->f_vnode, filp);
if (error) {
+ vdrop(filp->f_vnode);
kfree(filp);
goto done;
}
@@ -603,6 +620,7 @@ linux_dev_open(struct cdev *dev, int oflags, int devty
error = devfs_set_cdevpriv(filp, linux_file_dtor);
if (error) {
filp->f_op->release(file->f_vnode, filp);
+ vdrop(filp->f_vnode);
kfree(filp);
}
done:
@@ -622,8 +640,7 @@ linux_dev_close(struct cdev *dev, int fflag, int devty
if ((error = devfs_get_cdevpriv((void **)&filp)) != 0)
return (error);
filp->f_flags = file->f_flag;
- devfs_clear_cdevpriv();
-
+ devfs_clear_cdevpriv();
return (0);
}
More information about the svn-src-head
mailing list