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-all mailing list