From owner-svn-src-head@freebsd.org Wed May 31 12:03:00 2017 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id A9DFBAFF25D; Wed, 31 May 2017 12:03:00 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 823C575A7E; Wed, 31 May 2017 12:03:00 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v4VC2x5k007001; Wed, 31 May 2017 12:02:59 GMT (envelope-from hselasky@FreeBSD.org) Received: (from hselasky@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v4VC2xod006998; Wed, 31 May 2017 12:02:59 GMT (envelope-from hselasky@FreeBSD.org) Message-Id: <201705311202.v4VC2xod006998@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: hselasky set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky Date: Wed, 31 May 2017 12:02:59 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r319316 - in head/sys/compat/linuxkpi/common: include/linux src X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 31 May 2017 12:03:00 -0000 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); }