xref: /freebsd-src/sys/compat/linuxkpi/common/include/linux/file.h (revision ef9ffb8594eee294334ced627755bf5b46b48f9f)
18d59ecb2SHans Petter Selasky /*-
28d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Isilon Systems, Inc.
38d59ecb2SHans Petter Selasky  * Copyright (c) 2010 iX Systems, Inc.
48d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Panasas, Inc.
5f5a9867bSHans Petter Selasky  * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
68d59ecb2SHans Petter Selasky  * All rights reserved.
78d59ecb2SHans Petter Selasky  *
88d59ecb2SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
98d59ecb2SHans Petter Selasky  * modification, are permitted provided that the following conditions
108d59ecb2SHans Petter Selasky  * are met:
118d59ecb2SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
128d59ecb2SHans Petter Selasky  *    notice unmodified, this list of conditions, and the following
138d59ecb2SHans Petter Selasky  *    disclaimer.
148d59ecb2SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
158d59ecb2SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
168d59ecb2SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
178d59ecb2SHans Petter Selasky  *
188d59ecb2SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
198d59ecb2SHans Petter Selasky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
208d59ecb2SHans Petter Selasky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
218d59ecb2SHans Petter Selasky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
228d59ecb2SHans Petter Selasky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
238d59ecb2SHans Petter Selasky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
248d59ecb2SHans Petter Selasky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
258d59ecb2SHans Petter Selasky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
268d59ecb2SHans Petter Selasky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
278d59ecb2SHans Petter Selasky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
288d59ecb2SHans Petter Selasky  */
29307f78f3SVladimir Kondratyev #ifndef	_LINUXKPI_LINUX_FILE_H_
30307f78f3SVladimir Kondratyev #define	_LINUXKPI_LINUX_FILE_H_
318d59ecb2SHans Petter Selasky 
328d59ecb2SHans Petter Selasky #include <sys/param.h>
338d59ecb2SHans Petter Selasky #include <sys/file.h>
348d59ecb2SHans Petter Selasky #include <sys/filedesc.h>
358d59ecb2SHans Petter Selasky #include <sys/refcount.h>
368d59ecb2SHans Petter Selasky #include <sys/capsicum.h>
378d59ecb2SHans Petter Selasky #include <sys/proc.h>
388d59ecb2SHans Petter Selasky 
398d59ecb2SHans Petter Selasky #include <linux/fs.h>
401e3db1deSHans Petter Selasky #include <linux/slab.h>
418d59ecb2SHans Petter Selasky 
428d59ecb2SHans Petter Selasky struct linux_file;
438d59ecb2SHans Petter Selasky 
448d59ecb2SHans Petter Selasky #undef file
458d59ecb2SHans Petter Selasky 
46*ef9ffb85SMark Johnston extern const struct fileops linuxfileops;
478d59ecb2SHans Petter Selasky 
488d59ecb2SHans Petter Selasky static inline struct linux_file *
498d59ecb2SHans Petter Selasky linux_fget(unsigned int fd)
508d59ecb2SHans Petter Selasky {
518d59ecb2SHans Petter Selasky 	struct file *file;
528d59ecb2SHans Petter Selasky 
535b1cfc99SHans Petter Selasky 	/* lookup file pointer by file descriptor index */
54513c7a6eSMateusz Guzik 	if (fget_unlocked(curthread, fd, &cap_no_rights, &file) != 0)
555b1cfc99SHans Petter Selasky 		return (NULL);
565b1cfc99SHans Petter Selasky 
575b1cfc99SHans Petter Selasky 	/* check if file handle really belongs to us */
585b1cfc99SHans Petter Selasky 	if (file->f_data == NULL ||
595b1cfc99SHans Petter Selasky 	    file->f_ops != &linuxfileops) {
605b1cfc99SHans Petter Selasky 		fdrop(file, curthread);
618d59ecb2SHans Petter Selasky 		return (NULL);
628d59ecb2SHans Petter Selasky 	}
635b1cfc99SHans Petter Selasky 	return ((struct linux_file *)file->f_data);
648d59ecb2SHans Petter Selasky }
658d59ecb2SHans Petter Selasky 
66f5a9867bSHans Petter Selasky extern void linux_file_free(struct linux_file *filp);
67f5a9867bSHans Petter Selasky 
688d59ecb2SHans Petter Selasky static inline void
698d59ecb2SHans Petter Selasky fput(struct linux_file *filp)
708d59ecb2SHans Petter Selasky {
71f5a9867bSHans Petter Selasky 	if (refcount_release(filp->_file == NULL ?
72f5a9867bSHans Petter Selasky 	    &filp->f_count : &filp->_file->f_count)) {
73f5a9867bSHans Petter Selasky 		linux_file_free(filp);
748d59ecb2SHans Petter Selasky 	}
758d59ecb2SHans Petter Selasky }
76f5a9867bSHans Petter Selasky 
77f5a9867bSHans Petter Selasky static inline unsigned int
78f5a9867bSHans Petter Selasky file_count(struct linux_file *filp)
79f5a9867bSHans Petter Selasky {
80f5a9867bSHans Petter Selasky 	return (filp->_file == NULL ?
81f5a9867bSHans Petter Selasky 	    filp->f_count : filp->_file->f_count);
828d59ecb2SHans Petter Selasky }
838d59ecb2SHans Petter Selasky 
848d59ecb2SHans Petter Selasky static inline void
858d59ecb2SHans Petter Selasky put_unused_fd(unsigned int fd)
868d59ecb2SHans Petter Selasky {
878d59ecb2SHans Petter Selasky 	struct file *file;
888d59ecb2SHans Petter Selasky 
89513c7a6eSMateusz Guzik 	if (fget_unlocked(curthread, fd, &cap_no_rights, &file) != 0) {
908d59ecb2SHans Petter Selasky 		return;
918d59ecb2SHans Petter Selasky 	}
928d59ecb2SHans Petter Selasky 	/*
938d59ecb2SHans Petter Selasky 	 * NOTE: We should only get here when the "fd" has not been
948d59ecb2SHans Petter Selasky 	 * installed, so no need to free the associated Linux file
958d59ecb2SHans Petter Selasky 	 * structure.
968d59ecb2SHans Petter Selasky 	 */
978d59ecb2SHans Petter Selasky 	fdclose(curthread, file, fd);
988d59ecb2SHans Petter Selasky 
998d59ecb2SHans Petter Selasky 	/* drop extra reference */
1008d59ecb2SHans Petter Selasky 	fdrop(file, curthread);
1018d59ecb2SHans Petter Selasky }
1028d59ecb2SHans Petter Selasky 
1038d59ecb2SHans Petter Selasky static inline void
1048d59ecb2SHans Petter Selasky fd_install(unsigned int fd, struct linux_file *filp)
1058d59ecb2SHans Petter Selasky {
1068d59ecb2SHans Petter Selasky 	struct file *file;
1078d59ecb2SHans Petter Selasky 
108513c7a6eSMateusz Guzik 	if (fget_unlocked(curthread, fd, &cap_no_rights, &file) != 0) {
109b6480353SHans Petter Selasky 		filp->_file = NULL;
110b6480353SHans Petter Selasky 	} else {
1118d59ecb2SHans Petter Selasky 		filp->_file = file;
1128d59ecb2SHans Petter Selasky 		finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops);
113f5a9867bSHans Petter Selasky 
114f5a9867bSHans Petter Selasky 		/* transfer reference count from "filp" to "file" */
115f5a9867bSHans Petter Selasky 		while (refcount_release(&filp->f_count) == 0)
116f5a9867bSHans Petter Selasky 			refcount_acquire(&file->f_count);
117b6480353SHans Petter Selasky 	}
1188d59ecb2SHans Petter Selasky 
1198d59ecb2SHans Petter Selasky 	/* drop the extra reference */
1208d59ecb2SHans Petter Selasky 	fput(filp);
1218d59ecb2SHans Petter Selasky }
1228d59ecb2SHans Petter Selasky 
1238d59ecb2SHans Petter Selasky static inline int
1248d59ecb2SHans Petter Selasky get_unused_fd(void)
1258d59ecb2SHans Petter Selasky {
1268d59ecb2SHans Petter Selasky 	struct file *file;
1278d59ecb2SHans Petter Selasky 	int error;
1288d59ecb2SHans Petter Selasky 	int fd;
1298d59ecb2SHans Petter Selasky 
1308d59ecb2SHans Petter Selasky 	error = falloc(curthread, &file, &fd, 0);
1318d59ecb2SHans Petter Selasky 	if (error)
1328d59ecb2SHans Petter Selasky 		return -error;
1338d59ecb2SHans Petter Selasky 	/* drop the extra reference */
1348d59ecb2SHans Petter Selasky 	fdrop(file, curthread);
1358d59ecb2SHans Petter Selasky 	return fd;
1368d59ecb2SHans Petter Selasky }
1378d59ecb2SHans Petter Selasky 
13852ba0576SHans Petter Selasky static inline int
13952ba0576SHans Petter Selasky get_unused_fd_flags(int flags)
14052ba0576SHans Petter Selasky {
14152ba0576SHans Petter Selasky 	struct file *file;
14252ba0576SHans Petter Selasky 	int error;
14352ba0576SHans Petter Selasky 	int fd;
14452ba0576SHans Petter Selasky 
14552ba0576SHans Petter Selasky 	error = falloc(curthread, &file, &fd, flags);
14652ba0576SHans Petter Selasky 	if (error)
14752ba0576SHans Petter Selasky 		return -error;
14852ba0576SHans Petter Selasky 	/* drop the extra reference */
14952ba0576SHans Petter Selasky 	fdrop(file, curthread);
15052ba0576SHans Petter Selasky 	return fd;
15152ba0576SHans Petter Selasky }
15252ba0576SHans Petter Selasky 
153a6b28ee0SHans Petter Selasky extern struct linux_file *linux_file_alloc(void);
154a6b28ee0SHans Petter Selasky 
1558d59ecb2SHans Petter Selasky static inline struct linux_file *
1568d59ecb2SHans Petter Selasky alloc_file(int mode, const struct file_operations *fops)
1578d59ecb2SHans Petter Selasky {
1588d59ecb2SHans Petter Selasky 	struct linux_file *filp;
1598d59ecb2SHans Petter Selasky 
160a6b28ee0SHans Petter Selasky 	filp = linux_file_alloc();
1618d59ecb2SHans Petter Selasky 	filp->f_op = fops;
1628d59ecb2SHans Petter Selasky 	filp->f_mode = mode;
1638d59ecb2SHans Petter Selasky 
164a6b28ee0SHans Petter Selasky 	return (filp);
1658d59ecb2SHans Petter Selasky }
1668d59ecb2SHans Petter Selasky 
1678d59ecb2SHans Petter Selasky struct fd {
1688d59ecb2SHans Petter Selasky 	struct linux_file *linux_file;
1698d59ecb2SHans Petter Selasky };
1708d59ecb2SHans Petter Selasky 
1718d59ecb2SHans Petter Selasky static inline void fdput(struct fd fd)
1728d59ecb2SHans Petter Selasky {
1738d59ecb2SHans Petter Selasky 	fput(fd.linux_file);
1748d59ecb2SHans Petter Selasky }
1758d59ecb2SHans Petter Selasky 
1768d59ecb2SHans Petter Selasky static inline struct fd fdget(unsigned int fd)
1778d59ecb2SHans Petter Selasky {
1788d59ecb2SHans Petter Selasky 	struct linux_file *f = linux_fget(fd);
1798d59ecb2SHans Petter Selasky 	return (struct fd){f};
1808d59ecb2SHans Petter Selasky }
1818d59ecb2SHans Petter Selasky 
1828d59ecb2SHans Petter Selasky #define	file		linux_file
183f5a9867bSHans Petter Selasky #define	fget(...)	linux_fget(__VA_ARGS__)
1848d59ecb2SHans Petter Selasky 
185307f78f3SVladimir Kondratyev #endif	/* _LINUXKPI_LINUX_FILE_H_ */
186