static int recv_fds(int minor, struct ancillary *data, struct msg_control *msg_ctrl) { int rc, i, j; struct msghdr msghdr; struct cmsghdr *cmsg; endpoint_t to_ep; #if DEBUG == 1 static int call_count = 0; printf("(uds) [%d] recv_fds() call_count=%d\n", minor, ++call_count); #endif msghdr.msg_control = msg_ctrl->msg_control; msghdr.msg_controllen = msg_ctrl->msg_controllen; cmsg = CMSG_FIRSTHDR(&msghdr); cmsg->cmsg_len = CMSG_LEN(sizeof(int) * data->nfiledes); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; to_ep = uds_fd_table[minor].owner; /* copy to the target endpoint */ for (i = 0; i < data->nfiledes; i++) { rc = copy_filp(to_ep, data->filps[i]); if (rc < 0) { /* revert set_filp() calls */ for (j = 0; j < data->nfiledes; j++) { put_filp(data->filps[j]); } /* revert copy_filp() calls */ for (j = i; j >= 0; j--) { cancel_fd(to_ep, data->fds[j]); } return rc; } data->fds[i] = rc; /* data->fds[i] now has the new FD */ } for (i = 0; i < data->nfiledes; i++) { put_filp(data->filps[i]); #if DEBUG == 1 printf("(uds) recv_fds() => %d\n", data->fds[i]); #endif ((int *)CMSG_DATA(cmsg))[i] = data->fds[i]; data->fds[i] = -1; data->filps[i] = NULL; } data->nfiledes = 0; return OK; }
static int send_fds(int minor, struct ancillary *data) { int rc, i, j; #if DEBUG == 1 static int call_count = 0; printf("(uds) [%d] send_fds() call_count=%d\n", minor, ++call_count); #endif /* verify the file descriptors and get their filps. */ for (i = 0; i < data->nfiledes; i++) { data->filps[i] = verify_fd(uds_fd_table[minor].owner, data->fds[i]); if (data->filps[i] == NULL) { return EINVAL; } } /* set them as in-flight */ for (i = 0; i < data->nfiledes; i++) { rc = set_filp(data->filps[i]); if (rc != OK) { /* revert set_filp() calls */ for (j = i; j >= 0; j--) { put_filp(data->filps[j]); } return rc; } } return OK; }
struct file *dentry_open(const struct path *path, int flags, const struct cred *cred) { int error; struct file *f; validate_creds(cred); BUG_ON(!path->mnt); f = get_empty_filp(); if (!IS_ERR(f)) { f->f_flags = flags; f->f_path = *path; error = do_dentry_open(f, NULL, cred); if (!error) { error = open_check_o_direct(f); if (error) { fput(f); f = ERR_PTR(error); } } else { put_filp(f); f = ERR_PTR(error); } } return f; }
static struct file *vperfctr_get_filp(void) { struct file *filp; struct inode *inode; struct dentry *dentry; filp = get_empty_filp(); if (!filp) goto out; inode = vperfctr_get_inode(); if (!inode) goto out_filp; dentry = vperfctr_d_alloc_root(inode); if (!dentry) goto out_inode; filp->f_vfsmnt = mntget(vperfctr_mnt); filp->f_dentry = dentry; filp->f_mapping = dentry->d_inode->i_mapping; filp->f_pos = 0; filp->f_flags = 0; filp->f_op = &vperfctr_file_ops; /* fops_get() if MODULE */ filp->f_mode = FMODE_READ; filp->f_version = 0; return filp; out_inode: iput(inode); out_filp: put_filp(filp); /* doesn't run ->release() like fput() does */ out: return NULL; }
struct file *dentry_open(const struct path *path, int flags, const struct cred *cred) { int error; struct file *f; validate_creds(cred); /* We must always pass in a valid mount pointer. */ BUG_ON(!path->mnt); f = get_empty_filp(); if (!IS_ERR(f)) { f->f_flags = flags; f->f_path = *path; error = do_dentry_open(f, NULL, cred); if (!error) { /* from now on we need fput() to dispose of f */ error = open_check_o_direct(f); if (error) { fput(f); f = ERR_PTR(error); } } else { put_filp(f); f = ERR_PTR(error); } } return f; }
struct file *dentry_open(const struct path *path, int flags, const struct cred *cred) { int error; struct file *f; validate_creds(cred); /* We must always pass in a valid mount pointer. */ BUG_ON(!path->mnt); error = -ENFILE; f = get_empty_filp(); if (f == NULL) return ERR_PTR(error); f->f_flags = flags; error = vfs_open(path, f, cred); if (!error) { error = open_check_o_direct(f); if (error) { fput(f); f = ERR_PTR(error); } } else { put_filp(f); f = ERR_PTR(error); } return f; }
int clear_fds(int minor, struct ancillary *data) { /* This function calls put_filp() for all of the FDs in data. * This is used when a Unix Domain Socket is closed and there * exists references to file descriptors that haven't been received * with recvmsg(). */ int i; #if DEBUG == 1 static int call_count = 0; printf("(uds) [%d] recv_fds() call_count=%d\n", minor, ++call_count); #endif for (i = 0; i < data->nfiledes; i++) { put_filp(data->filps[i]); #if DEBUG == 1 printf("(uds) clear_fds() => %d\n", data->fds[i]); #endif data->fds[i] = -1; data->filps[i] = NULL; } data->nfiledes = 0; return OK; }
struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { struct file * f; struct inode *inode; int error; error = -ENFILE; f = get_empty_filp(); if (!f) goto cleanup_dentry; f->f_flags = flags; f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_file; } f->f_mapping = inode->i_mapping; f->f_dentry = dentry; f->f_vfsmnt = mnt; f->f_pos = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); if (f->f_op && f->f_op->open) { error = f->f_op->open(inode,f); if (error) goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); /* NB: we're sure to have correct a_ops only after f_op->open */ if (f->f_flags & O_DIRECT) { if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) put_write_access(inode); file_kill(f); f->f_dentry = NULL; f->f_vfsmnt = NULL; cleanup_file: put_filp(f); cleanup_dentry: dput(dentry); mntput(mnt); return ERR_PTR(error); }
/* * shmem_file_setup - get an unlinked file living in tmpfs * * @name: name for dentry (to be seen in /proc/<pid>/maps * @size: size to be set for the file * */ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags) { int error; struct file *file; struct inode *inode; struct dentry *dentry, *root; struct qstr this; if (IS_ERR(shm_mnt)) return (void *)shm_mnt; error = -ENOMEM; this.name = name; this.len = strlen(name); this.hash = 0; /* will go */ root = shm_mnt->mnt_root; dentry = d_alloc(root, &this); if (!dentry) goto put_memory; error = -ENFILE; file = get_empty_filp(); if (!file) goto put_dentry; error = -ENOSPC; inode = ramfs_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0); if (!inode) goto close_file; d_instantiate(dentry, inode); inode->i_nlink = 0; /* It is unlinked */ file->f_path.mnt = mntget(shm_mnt); file->f_path.dentry = dentry; file->f_mapping = inode->i_mapping; file->f_op = &ramfs_file_operations; file->f_mode = FMODE_WRITE | FMODE_READ; /* notify everyone as to the change of file size */ error = do_truncate(dentry, size, 0, file); if (error < 0) goto close_file; return file; close_file: put_filp(file); put_dentry: dput(dentry); put_memory: return ERR_PTR(error); }
int remove_physical_dir (struct file *file) { struct dentry *dentry; struct inode *dir; int res = 0; dentry = file->f_dentry; dir = dentry->d_parent->d_inode; res = vfs_rmdir (dir, dentry); dput (dentry); put_filp (file); return res; }
struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { struct file * f; struct inode *inode; int error; error = -ENFILE; f = get_empty_filp(); if (!f) goto cleanup_dentry; f->f_flags = flags; f->f_mode = (flags+1) & O_ACCMODE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_file; } f->f_dentry = dentry; f->f_vfsmnt = mnt; f->f_pos = 0; f->f_reada = 0; f->f_op = fops_get(inode->i_fop); if (inode->i_sb) file_move(f, &inode->i_sb->s_files); if (f->f_op && f->f_op->open) { error = f->f_op->open(inode,f); if (error) goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); return f; cleanup_all: fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) put_write_access(inode); f->f_dentry = NULL; f->f_vfsmnt = NULL; cleanup_file: put_filp(f); cleanup_dentry: dput(dentry); mntput(mnt); return ERR_PTR(error); }
static struct file *__dentry_open(struct path *path, struct file *f, int (*open)(struct inode *, struct file *), const struct cred *cred) { struct file *res = do_dentry_open(path, f, open, cred); if (!IS_ERR(res)) { int error = open_check_o_direct(f); if (error) { fput(res); res = ERR_PTR(error); } } else { put_filp(f); } return res; }
struct file *filp_clone_open(struct file *oldfile) { struct file *file; int retval; file = get_empty_filp(); if (IS_ERR(file)) return file; file->f_flags = oldfile->f_flags; retval = vfs_open(&oldfile->f_path, file, oldfile->f_cred); if (retval) { put_filp(file); return ERR_PTR(retval); } return file; }
/* * Note that while the flag value (low two bits) for sys_open means: * 00 - read-only * 01 - write-only * 10 - read-write * 11 - special * it is changed into * 00 - no permissions needed * 01 - read-permission * 10 - write-permission * 11 - read-write * for the internal routines (ie open_namei()/follow_link() etc). 00 is * used by symlinks. */ struct file *filp_open(const char * filename, int flags, int mode) { int namei_flags, error; struct nameidata nd; struct file *f; namei_flags = flags; if ((namei_flags+1) & O_ACCMODE) namei_flags++; if (namei_flags & O_TRUNC) namei_flags |= 2; error = -ENFILE; f = get_empty_filp(); if (f == NULL) return ERR_PTR(error); error = open_namei(filename, namei_flags, mode, &nd); if (!error) return __dentry_open(nd.dentry, nd.mnt, flags, f); put_filp(f); return ERR_PTR(error); }
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, struct file *f, int (*open)(struct inode *, struct file *), const struct cred *cred) { static const struct file_operations empty_fops = {}; struct inode *inode; int error; f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; if (unlikely(f->f_flags & O_PATH)) f->f_mode = FMODE_PATH; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = __get_file_write_access(inode, mnt); if (error) goto cleanup_file; if (!special_file(inode->i_mode)) file_take_write(f); } f->f_mapping = inode->i_mapping; f->f_path.dentry = dentry; f->f_path.mnt = mnt; f->f_pos = 0; file_sb_list_add(f, inode->i_sb); if (unlikely(f->f_mode & FMODE_PATH)) { f->f_op = &empty_fops; return f; } f->f_op = fops_get(inode->i_fop); error = security_dentry_open(f, cred); if (error) goto cleanup_all; error = break_lease(inode, f->f_flags); if (error) goto cleanup_all; if (!open && f->f_op) open = f->f_op->open; if (open) { error = open(inode, f); if (error) goto cleanup_all; } if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(inode); f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); /* NB: we're sure to have correct a_ops only after f_op->open */ if (f->f_flags & O_DIRECT) { if (!f->f_mapping->a_ops || ((!f->f_mapping->a_ops->direct_IO) && (!f->f_mapping->a_ops->get_xip_mem))) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) { put_write_access(inode); if (!special_file(inode->i_mode)) { /* * We don't consider this a real * mnt_want/drop_write() pair * because it all happenend right * here, so just reset the state. */ file_reset_write(f); mnt_drop_write(mnt); } } file_sb_list_del(f); f->f_path.dentry = NULL; f->f_path.mnt = NULL; cleanup_file: put_filp(f); dput(dentry); mntput(mnt); return ERR_PTR(error); }
static struct file *__dentry_open(struct _dentry *dentry, struct vfsmount *mnt, int flags, struct file *f, int (*open)(struct _inode *, struct file *)) { struct _inode *inode; int error; struct super_block *sb; struct _file *_f = tx_cache_get_file(f); _f->f_flags = flags; _f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; inode = d_get_inode(dentry); sb = inode->i_sb; if (_f->f_mode & FMODE_WRITE) { error = get_write_access(parent(inode)); if (error) goto cleanup_file; } f->f_mapping = inode->i_mapping; _f->f_path.dentry = parent(dentry); _f->f_path.mnt = mnt; _f->f_pos = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &sb->s_files); if (!open && f->f_op) open = f->f_op->open; if (open) { error = open(inode, f); if (error) goto cleanup_all; } _f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, tx_cache_get_inode(f->f_mapping->host)->i_mapping); /* NB: we're sure to have correct a_ops only after f_op->open */ if (_f->f_flags & O_DIRECT) { if (!f->f_mapping->a_ops || ((!f->f_mapping->a_ops->direct_IO) && (!f->f_mapping->a_ops->get_xip_page))) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: fops_put(f->f_op); if (_f->f_mode & FMODE_WRITE) put_write_access(parent(inode)); file_kill(f); _f->f_path.dentry = NULL; _f->f_path.mnt = NULL; cleanup_file: /* Avoid issues if we recycle this object */ if(live_transaction()) early_release(&f->xobj, 1); put_filp(f); dput(parent(dentry)); mntput(mnt); return ERR_PTR(error); }
int do_pipe(int *fd) { struct inode * inode; struct file *f1, *f2; int error; int i,j; error = -ENFILE; f1 = get_empty_filp(); if (!f1) goto no_files; f2 = get_empty_filp(); if (!f2) goto close_f1; inode = get_pipe_inode(); if (!inode) goto close_f12; error = get_unused_fd(); if (error < 0) goto close_f12_inode; i = error; error = get_unused_fd(); if (error < 0) goto close_f12_inode_i; j = error; error = -ENOMEM; f1->f_dentry = f2->f_dentry = dget(d_alloc_root(inode, NULL)); if (!f1->f_dentry) goto close_f12_inode_i_j; /* read file */ f1->f_pos = f2->f_pos = 0; f1->f_flags = O_RDONLY; f1->f_op = &read_pipe_fops; f1->f_mode = 1; /* write file */ f2->f_flags = O_WRONLY; f2->f_op = &write_pipe_fops; f2->f_mode = 2; fd_install(i, f1); fd_install(j, f2); fd[0] = i; fd[1] = j; return 0; close_f12_inode_i_j: put_unused_fd(j); close_f12_inode_i: put_unused_fd(i); close_f12_inode: free_page((unsigned long) PIPE_BASE(*inode)); iput(inode); close_f12: put_filp(f2); close_f1: put_filp(f1); no_files: return error; }
/** * anon_inode_getfd - creates a new file instance by hooking it up to and * anonymous inode, and a dentry that describe the "class" * of the file * * @pfd: [out] pointer to the file descriptor * @dpinode: [out] pointer to the inode * @pfile: [out] pointer to the file struct * @name: [in] name of the "class" of the new file * @fops [in] file operations for the new file * @priv [in] private data for the new file (will be file's private_data) * * Creates a new file by hooking it on a single inode. This is useful for files * that do not need to have a full-fledged inode in order to operate correctly. * All the files created with anon_inode_getfd() will share a single inode, by * hence saving memory and avoiding code duplication for the file/inode/dentry * setup. */ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, const char *name, const struct file_operations *fops, void *priv) { struct qstr this; struct dentry *dentry; struct _dentry *_dentry; struct inode *inode; struct _inode *_inode; struct file *file; struct _file *_file; int error, fd; if (IS_ERR(anon_inode_inode)) return -ENODEV; file = get_empty_filp(); if (!file) return -ENFILE; _file = tx_cache_get_file(file); inode = igrab(anon_inode_inode); if (IS_ERR(inode)) { error = PTR_ERR(inode); goto err_put_filp; } _inode = tx_cache_get_inode(inode); error = get_unused_fd(); if (error < 0) goto err_iput; fd = error; /* * Link the inode to a directory entry by creating a unique name * using the inode sequence number. */ error = -ENOMEM; this.name = name; this.len = strlen(name); this.hash = 0; dentry = d_alloc(tx_cache_get_dentry(anon_inode_mnt->mnt_sb->s_root), &this); if (!dentry) goto err_put_unused_fd; _dentry = tx_cache_get_dentry(dentry); _dentry->d_op = &anon_inodefs_dentry_operations; /* Do not publish this dentry inside the global dentry hash table */ _dentry->d_flags &= ~DCACHE_UNHASHED; d_instantiate(_dentry, _inode); _file->f_path.mnt = mntget(anon_inode_mnt); _file->f_path.dentry = dentry; file->f_mapping = _inode->i_mapping; _file->f_pos = 0; _file->f_flags = O_RDWR; file->f_op = fops; _file->f_mode = FMODE_READ | FMODE_WRITE; _file->f_version = 0; file->private_data = priv; fd_install(fd, file); *pfd = fd; *pinode = inode; *pfile = file; return 0; err_put_unused_fd: put_unused_fd(fd); err_iput: iput(inode); err_put_filp: put_filp(file); return error; }
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, struct file *f) { struct inode *inode; static LIST_HEAD(kill_list); int error; f->f_flags = flags; f->f_mode = (flags+1) & O_ACCMODE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_file; } f->f_dentry = dentry; f->f_vfsmnt = mnt; f->f_pos = 0; f->f_reada = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); /* preallocate kiobuf for O_DIRECT */ f->f_iobuf = NULL; f->f_iobuf_lock = 0; if (f->f_flags & O_DIRECT) { error = alloc_kiovec(1, &f->f_iobuf); if (error) goto cleanup_all; } if (f->f_op && f->f_op->open) { error = f->f_op->open(inode,f); if (error) goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); /* NB: we're sure to have correct a_ops only after f_op->open */ if (f->f_flags & O_DIRECT) { if (!inode->i_mapping || !inode->i_mapping->a_ops || !(inode->i_mapping->a_ops->direct_IO || inode->i_mapping->a_ops->direct_sector_IO)) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: if (f->f_iobuf) free_kiovec(1, &f->f_iobuf); fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) put_write_access(inode); file_move(f, &kill_list); /* out of the way.. */ f->f_dentry = NULL; f->f_vfsmnt = NULL; cleanup_file: put_filp(f); dput(dentry); mntput(mnt); return ERR_PTR(error); }
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, struct file *f, int (*open)(struct inode *, struct file *)) { struct inode *inode; int error; f->f_flags = flags; f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = __get_file_write_access(inode, mnt); if (error) goto cleanup_file; if (!special_file(inode->i_mode)) file_take_write(f); } f->f_mapping = inode->i_mapping; f->f_path.dentry = dentry; f->f_path.mnt = mnt; f->f_pos = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); error = security_dentry_open(f); if (error) goto cleanup_all; if (!open && f->f_op) open = f->f_op->open; if (open) { error = open(inode, f); if (error) goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); /* NB: we're sure to have correct a_ops only after f_op->open */ if (f->f_flags & O_DIRECT) { if (!f->f_mapping->a_ops || ((!f->f_mapping->a_ops->direct_IO) && (!f->f_mapping->a_ops->get_xip_mem))) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) { put_write_access(inode); if (!special_file(inode->i_mode)) { /* * We don't consider this a real * mnt_want/drop_write() pair * because it all happenend right * here, so just reset the state. */ file_reset_write(f); mnt_drop_write(mnt); } } file_kill(f); f->f_path.dentry = NULL; f->f_path.mnt = NULL; cleanup_file: put_filp(f); dput(dentry); mntput(mnt); return ERR_PTR(error); }
/** * lookup_instantiate_filp - instantiates the open intent filp * @nd: pointer to nameidata * @dentry: pointer to dentry * @open: open callback * * Helper for filesystems that want to use lookup open intents and pass back * a fully instantiated struct file to the caller. * This function is meant to be called from within a filesystem's * lookup method. * Beware of calling it for non-regular files! Those ->open methods might block * (e.g. in fifo_open), leaving you with parent locked (and in case of fifo, * leading to a deadlock, as nobody can open that fifo anymore, because * another process to open fifo will block on locked parent when doing lookup). * Note that in case of error, nd->intent.open.file is destroyed, but the * path information remains valid. * If the open callback is set to NULL, then the standard f_op->open() * filesystem callback is substituted. */ struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, int (*open)(struct inode *, struct file *)) { struct path path = { .dentry = dentry, .mnt = nd->path.mnt }; const struct cred *cred = current_cred(); if (IS_ERR(nd->intent.open.file)) goto out; if (IS_ERR(dentry)) goto out_err; nd->intent.open.file = __dentry_open(&path, nd->intent.open.file, open, cred); out: return nd->intent.open.file; out_err: release_open_intent(nd); nd->intent.open.file = (struct file *)dentry; goto out; } EXPORT_SYMBOL_GPL(lookup_instantiate_filp); /** * nameidata_to_filp - convert a nameidata to an open filp. * @nd: pointer to nameidata * @flags: open flags * * Note that this function destroys the original nameidata */ struct file *nameidata_to_filp(struct nameidata *nd) { const struct cred *cred = current_cred(); struct file *filp; /* Pick up the filp from the open intent */ filp = nd->intent.open.file; nd->intent.open.file = NULL; /* Has the filesystem initialised the file for us? */ if (filp->f_path.dentry == NULL) { struct inode *inode = nd->path.dentry->d_inode; if (inode->i_op->open) { int flags = filp->f_flags; put_filp(filp); filp = inode->i_op->open(nd->path.dentry, flags, cred); } else { filp = __dentry_open(&nd->path, filp, NULL, cred); } } return filp; } /* * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an * error. */ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, const struct cred *cred) { struct path path = { .dentry = dentry, .mnt = mnt }; struct file *ret; /* We must always pass in a valid mount pointer. */ BUG_ON(!mnt); ret = vfs_open(&path, flags, cred); path_put(&path); return ret; } EXPORT_SYMBOL(dentry_open); /** * vfs_open - open the file at the given path * @path: path to open * @flags: open flags * @cred: credentials to use * * Open the file. If successful, the returned file will have acquired * an additional reference for path. */ struct file *vfs_open(struct path *path, int flags, const struct cred *cred) { struct file *f; struct inode *inode = path->dentry->d_inode; validate_creds(cred); if (inode->i_op->open) return inode->i_op->open(path->dentry, flags, cred); f = get_empty_filp(); if (f == NULL) return ERR_PTR(-ENFILE); f->f_flags = flags; return __dentry_open(path, f, NULL, cred); } EXPORT_SYMBOL(vfs_open); static void __put_unused_fd(struct files_struct *files, unsigned int fd) { struct fdtable *fdt = files_fdtable(files); __FD_CLR(fd, fdt->open_fds); if (fd < files->next_fd) files->next_fd = fd; } void put_unused_fd(unsigned int fd) { struct files_struct *files = current->files; spin_lock(&files->file_lock); __put_unused_fd(files, fd); spin_unlock(&files->file_lock); } EXPORT_SYMBOL(put_unused_fd); /* * Install a file pointer in the fd array. * * The VFS is full of places where we drop the files lock between * setting the open_fds bitmap and installing the file in the file * array. At any such point, we are vulnerable to a dup2() race * installing a file in the array before us. We need to detect this and * fput() the struct file we are about to overwrite in this case. * * It should never happen - if we allow dup2() do it, _really_ bad things * will follow. */ void fd_install(unsigned int fd, struct file *file) { struct files_struct *files = current->files; struct fdtable *fdt; spin_lock(&files->file_lock); fdt = files_fdtable(files); BUG_ON(fdt->fd[fd] != NULL); rcu_assign_pointer(fdt->fd[fd], file); spin_unlock(&files->file_lock); } EXPORT_SYMBOL(fd_install); static inline int build_open_flags(int flags, int mode, struct open_flags *op) { int lookup_flags = 0; int acc_mode; if (!(flags & O_CREAT)) mode = 0; op->mode = mode; /* Must never be set by userspace */ flags &= ~FMODE_NONOTIFY; /* * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only * check for O_DSYNC if the need any syncing at all we enforce it's * always set instead of having to deal with possibly weird behaviour * for malicious applications setting only __O_SYNC. */ if (flags & __O_SYNC) flags |= O_DSYNC; /* * If we have O_PATH in the open flag. Then we * cannot have anything other than the below set of flags */ if (flags & O_PATH) { flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH; acc_mode = 0; } else { acc_mode = MAY_OPEN | ACC_MODE(flags); } op->open_flag = flags; /* O_TRUNC implies we need access checks for write permissions */ if (flags & O_TRUNC) acc_mode |= MAY_WRITE; /* Allow the LSM permission hook to distinguish append access from general write access. */ if (flags & O_APPEND) acc_mode |= MAY_APPEND; op->acc_mode = acc_mode; op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN; if (flags & O_CREAT) { op->intent |= LOOKUP_CREATE; if (flags & O_EXCL) op->intent |= LOOKUP_EXCL; } if (flags & O_DIRECTORY) lookup_flags |= LOOKUP_DIRECTORY; if (!(flags & O_NOFOLLOW)) lookup_flags |= LOOKUP_FOLLOW; return lookup_flags; }
int do_pipe(int *fd) { struct qstr this; char name[32]; struct dentry *dentry; struct inode * inode; struct file *f1, *f2; int error; int i,j; error = -ENFILE; f1 = get_empty_filp(); if (!f1) goto no_files; f2 = get_empty_filp(); if (!f2) goto close_f1; inode = get_pipe_inode(); if (!inode) goto close_f12; error = get_unused_fd(); if (error < 0) goto close_f12_inode; i = error; error = get_unused_fd(); if (error < 0) goto close_f12_inode_i; j = error; error = -ENOMEM; sprintf(name, "[%lu]", inode->i_ino); this.name = name; this.len = strlen(name); this.hash = inode->i_ino; /* will go */ dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this); if (!dentry) goto close_f12_inode_i_j; dentry->d_op = &pipefs_dentry_operations; d_add(dentry, inode); f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt)); f1->f_dentry = f2->f_dentry = dget(dentry); /* read file */ f1->f_pos = f2->f_pos = 0; f1->f_flags = O_RDONLY; f1->f_op = &read_pipe_fops; f1->f_mode = 1; f1->f_version = 0; /* write file */ f2->f_flags = O_WRONLY; f2->f_op = &write_pipe_fops; f2->f_mode = 2; f2->f_version = 0; fd_install(i, f1); fd_install(j, f2); fd[0] = i; fd[1] = j; return 0; close_f12_inode_i_j: put_unused_fd(j); close_f12_inode_i: put_unused_fd(i); close_f12_inode: free_page((unsigned long) PIPE_BASE(*inode)); kfree(inode->i_pipe); inode->i_pipe = NULL; iput(inode); close_f12: put_filp(f2); close_f1: put_filp(f1); no_files: return error; }
struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { struct file * f; struct inode *inode; static LIST_HEAD(kill_list); int error; error = -ENFILE; f = get_empty_filp(); if (!f) goto cleanup_dentry; f->f_flags = flags; f->f_mode = (flags+1) & O_ACCMODE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_file; } f->f_dentry = dentry; f->f_vfsmnt = mnt; f->f_pos = 0; f->f_reada = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); /* preallocate kiobuf for O_DIRECT */ f->f_iobuf = NULL; f->f_iobuf_lock = 0; if (f->f_flags & O_DIRECT) { error = alloc_kiovec(1, &f->f_iobuf); if (error) goto cleanup_all; } if (f->f_op && f->f_op->open) { error = f->f_op->open(inode,f); if (error) goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); return f; cleanup_all: if (f->f_iobuf) free_kiovec(1, &f->f_iobuf); fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) put_write_access(inode); file_move(f, &kill_list); /* out of the way.. */ f->f_dentry = NULL; f->f_vfsmnt = NULL; cleanup_file: put_filp(f); cleanup_dentry: dput(dentry); mntput(mnt); return ERR_PTR(error); }