int fuse_release_common(struct inode *inode, struct file *file, int isdir) { struct fuse_file *ff = file->private_data; if (ff) { struct fuse_conn *fc = get_fuse_conn(inode); u64 nodeid = get_node_id(inode); fuse_send_release(fc, ff, nodeid, inode, file->f_flags, isdir); } /* Return value is ignored by VFS */ return 0; }
/* * Atomic create+open operation * * If the filesystem doesn't support this, then fall back to separate * 'mknod' + 'open' requests. */ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, struct nameidata *nd) { int err; struct inode *inode; struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_req *req; struct fuse_open_in inarg; struct fuse_open_out outopen; struct fuse_entry_out outentry; struct fuse_file *ff; struct file *file; int flags = nd->intent.open.flags - 1; err = -ENOSYS; if (fc->no_create) goto out; err = -EINTR; req = fuse_get_request(fc); if (!req) goto out; ff = fuse_file_alloc(); if (!ff) goto out_put_request; flags &= ~O_NOCTTY; memset(&inarg, 0, sizeof(inarg)); inarg.flags = flags; inarg.mode = mode; req->in.h.opcode = FUSE_CREATE; req->in.h.nodeid = get_node_id(dir); req->inode = dir; req->in.numargs = 2; req->in.args[0].size = sizeof(inarg); req->in.args[0].value = &inarg; req->in.args[1].size = entry->d_name.len + 1; req->in.args[1].value = entry->d_name.name; req->out.numargs = 2; req->out.args[0].size = sizeof(outentry); req->out.args[0].value = &outentry; req->out.args[1].size = sizeof(outopen); req->out.args[1].value = &outopen; request_send(fc, req); err = req->out.h.error; if (err) { if (err == -ENOSYS) fc->no_create = 1; goto out_free_ff; } err = -EIO; if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) goto out_free_ff; inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, &outentry.attr); err = -ENOMEM; if (!inode) { flags &= ~(O_CREAT | O_EXCL | O_TRUNC); ff->fh = outopen.fh; /* Special release, with inode = NULL, this will trigger a 'forget' request when the release is complete */ fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0); goto out_put_request; } fuse_put_request(fc, req); d_instantiate(entry, inode); fuse_change_timeout(entry, &outentry); file = lookup_instantiate_filp(nd, entry, generic_file_open); if (IS_ERR(file)) { ff->fh = outopen.fh; fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0); return PTR_ERR(file); } fuse_finish_open(inode, file, ff, &outopen); return 0; out_free_ff: fuse_file_free(ff); out_put_request: fuse_put_request(fc, req); out: return err; }