Message ID | 20210916084045.31684-8-hreitz@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | virtiofsd: Allow using file handles instead of O_PATH FDs | expand |
On Thu, Sep 16, 2021 at 10:40:40AM +0200, Hanna Reitz wrote: > Strictly speaking, this is not necessary, because lo_inode_open() will > always return a new FD owned by the caller, so TempFd.owned will always > be true. > > The auto-cleanup is nice, though. Also, we get a more unified interface > where you always get a TempFd when you need an FD for an lo_inode > (regardless of whether it is an O_PATH FD or a non-O_PATH FD). > > Signed-off-by: Hanna Reitz <hreitz@redhat.com> > --- > tools/virtiofsd/passthrough_ll.c | 156 +++++++++++++++---------------- > 1 file changed, 75 insertions(+), 81 deletions(-) > > diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c > index 3bf20b8659..d257eda129 100644 > --- a/tools/virtiofsd/passthrough_ll.c > +++ b/tools/virtiofsd/passthrough_ll.c > @@ -293,10 +293,8 @@ static void temp_fd_clear(TempFd *temp_fd) > /** > * Return an owned fd from *temp_fd that will not be closed when > * *temp_fd goes out of scope. > - * > - * (TODO: Remove __attribute__ once this is used.) > */ > -static __attribute__((unused)) int temp_fd_steal(TempFd *temp_fd) > +static int temp_fd_steal(TempFd *temp_fd) > { > if (temp_fd->owned) { > temp_fd->owned = false; > @@ -309,10 +307,8 @@ static __attribute__((unused)) int temp_fd_steal(TempFd *temp_fd) > /** > * Create a borrowing copy of an existing TempFd. Note that *to is > * only valid as long as *from is valid. > - * > - * (TODO: Remove __attribute__ once this is used.) > */ > -static __attribute__((unused)) void temp_fd_copy(const TempFd *from, TempFd *to) > +static void temp_fd_copy(const TempFd *from, TempFd *to) > { > *to = (TempFd) { > .fd = from->fd, > @@ -689,9 +685,12 @@ static int lo_fd(fuse_req_t req, fuse_ino_t ino, TempFd *tfd) > * when a malicious client opens special files such as block device nodes. > * Symlink inodes are also rejected since symlinks must already have been > * traversed on the client side. > + * > + * The fd is returned in tfd->fd. The return value is 0 on success and -errno > + * otherwise. > */ > static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode, > - int open_flags) > + int open_flags, TempFd *tfd) > { > g_autofree char *fd_str = g_strdup_printf("%d", inode->fd); > int fd; > @@ -710,7 +709,13 @@ static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode, > if (fd < 0) { > return -errno; > } > - return fd; > + > + *tfd = (TempFd) { > + .fd = fd, > + .owned = true, > + }; > + > + return 0; > } > > static void lo_init(void *userdata, struct fuse_conn_info *conn) > @@ -854,7 +859,8 @@ static int lo_fi_fd(fuse_req_t req, struct fuse_file_info *fi) > static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, > int valid, struct fuse_file_info *fi) > { > - g_auto(TempFd) path_fd = TEMP_FD_INIT; > + g_auto(TempFd) path_fd = TEMP_FD_INIT; /* at least an O_PATH fd */ What does atleast O_PATH fd mean? > + g_auto(TempFd) rw_fd = TEMP_FD_INIT; /* O_RDWR fd */ > int saverr; > char procname[64]; > struct lo_data *lo = lo_data(req); > @@ -868,7 +874,15 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, > return; > } > > - res = lo_inode_fd(inode, &path_fd); > + if (!fi && (valid & FUSE_SET_ATTR_SIZE)) { > + /* We need an O_RDWR FD for ftruncate() */ > + res = lo_inode_open(lo, inode, O_RDWR, &rw_fd); > + if (res >= 0) { > + temp_fd_copy(&rw_fd, &path_fd); I am lost here. If lo_inode_open() failed, why are we calling this temp_fd_copy()? path_fd is not even a valid fd yet. Still beats me that why open rw_fd now instead of down in FUSE_SET_ATTR_SIZE block. I think we had this discussion and you had some reasons to move it up. Vivek > + } > + } else { > + res = lo_inode_fd(inode, &path_fd); > + } > if (res < 0) { > saverr = -res; > goto out_err; > @@ -916,18 +930,12 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, > if (fi) { > truncfd = fd; > } else { > - truncfd = lo_inode_open(lo, inode, O_RDWR); > - if (truncfd < 0) { > - saverr = -truncfd; > - goto out_err; > - } > + assert(rw_fd.fd >= 0); > + truncfd = rw_fd.fd; > } > > saverr = drop_security_capability(lo, truncfd); > if (saverr) { > - if (!fi) { > - close(truncfd); > - } > goto out_err; > } > > @@ -935,9 +943,6 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, > res = drop_effective_cap("FSETID", &cap_fsetid_dropped); > if (res != 0) { > saverr = res; > - if (!fi) { > - close(truncfd); > - } > goto out_err; > } > } > @@ -950,9 +955,6 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, > fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_FSETID\n"); > } > } > - if (!fi) { > - close(truncfd); > - } > if (res == -1) { > goto out_err; > } > @@ -1840,11 +1842,13 @@ static struct lo_dirp *lo_dirp(fuse_req_t req, struct fuse_file_info *fi) > static void lo_opendir(fuse_req_t req, fuse_ino_t ino, > struct fuse_file_info *fi) > { > + g_auto(TempFd) rd_fd = TEMP_FD_INIT; > int error = ENOMEM; > struct lo_data *lo = lo_data(req); > struct lo_inode *inode; > struct lo_dirp *d = NULL; > int fd; > + int res; > ssize_t fh; > > inode = lo_inode(req, ino); > @@ -1858,14 +1862,16 @@ static void lo_opendir(fuse_req_t req, fuse_ino_t ino, > goto out_err; > } > > - fd = lo_inode_open(lo, inode, O_RDONLY); > - if (fd < 0) { > - error = -fd; > + res = lo_inode_open(lo, inode, O_RDONLY, &rd_fd); > + if (res < 0) { > + error = -res; > goto out_err; > } > > + fd = temp_fd_steal(&rd_fd); > d->dp = fdopendir(fd); > if (d->dp == NULL) { > + close(fd); > goto out_errno; > } > > @@ -1895,8 +1901,6 @@ out_err: > if (d) { > if (d->dp) { > closedir(d->dp); > - } else if (fd != -1) { > - close(fd); > } > free(d); > } > @@ -2096,6 +2100,7 @@ static void update_open_flags(int writeback, int allow_direct_io, > static int lo_do_open(struct lo_data *lo, struct lo_inode *inode, > int existing_fd, struct fuse_file_info *fi) > { > + g_auto(TempFd) opened_fd = TEMP_FD_INIT; > ssize_t fh; > int fd = existing_fd; > int err; > @@ -2112,16 +2117,18 @@ static int lo_do_open(struct lo_data *lo, struct lo_inode *inode, > } > } > > - fd = lo_inode_open(lo, inode, fi->flags); > + err = lo_inode_open(lo, inode, fi->flags, &opened_fd); > > if (cap_fsetid_dropped) { > if (gain_effective_cap("FSETID")) { > fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_FSETID\n"); > } > } > - if (fd < 0) { > - return -fd; > + if (err < 0) { > + return -err; > } > + fd = temp_fd_steal(&opened_fd); > + > if (fi->flags & (O_TRUNC)) { > int err = drop_security_capability(lo, fd); > if (err) { > @@ -2231,8 +2238,9 @@ static struct lo_inode_plock *lookup_create_plock_ctx(struct lo_data *lo, > uint64_t lock_owner, > pid_t pid, int *err) > { > + g_auto(TempFd) rw_fd = TEMP_FD_INIT; > struct lo_inode_plock *plock; > - int fd; > + int res; > > plock = > g_hash_table_lookup(inode->posix_locks, GUINT_TO_POINTER(lock_owner)); > @@ -2249,15 +2257,15 @@ static struct lo_inode_plock *lookup_create_plock_ctx(struct lo_data *lo, > > /* Open another instance of file which can be used for ofd locks. */ > /* TODO: What if file is not writable? */ > - fd = lo_inode_open(lo, inode, O_RDWR); > - if (fd < 0) { > - *err = -fd; > + res = lo_inode_open(lo, inode, O_RDWR, &rw_fd); > + if (res < 0) { > + *err = -res; > free(plock); > return NULL; > } > > plock->lock_owner = lock_owner; > - plock->fd = fd; > + plock->fd = temp_fd_steal(&rw_fd); > g_hash_table_insert(inode->posix_locks, GUINT_TO_POINTER(plock->lock_owner), > plock); > return plock; > @@ -2473,6 +2481,7 @@ static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) > static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, > struct fuse_file_info *fi) > { > + g_auto(TempFd) rw_fd = TEMP_FD_INIT; > struct lo_inode *inode = lo_inode(req, ino); > struct lo_data *lo = lo_data(req); > int res; > @@ -2487,11 +2496,12 @@ static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, > } > > if (!fi) { > - fd = lo_inode_open(lo, inode, O_RDWR); > - if (fd < 0) { > - res = -fd; > + res = lo_inode_open(lo, inode, O_RDWR, &rw_fd); > + if (res < 0) { > + res = -res; > goto out; > } > + fd = rw_fd.fd; > } else { > fd = lo_fi_fd(req, fi); > } > @@ -2501,9 +2511,6 @@ static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, > } else { > res = fsync(fd) == -1 ? errno : 0; > } > - if (!fi) { > - close(fd); > - } > out: > lo_inode_put(lo, &inode); > fuse_reply_err(req, res); > @@ -3065,7 +3072,6 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, > struct lo_inode *inode; > ssize_t ret; > int saverr; > - int fd = -1; > > if (block_xattr(lo, in_name)) { > fuse_reply_err(req, EOPNOTSUPP); > @@ -3117,12 +3123,14 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, > * Otherwise, call fchdir() to avoid open(). > */ > if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { > - fd = lo_inode_open(lo, inode, O_RDONLY); > - if (fd < 0) { > - saverr = -fd; > + g_auto(TempFd) rd_fd = TEMP_FD_INIT; > + > + ret = lo_inode_open(lo, inode, O_RDONLY, &rd_fd); > + if (ret < 0) { > + saverr = -ret; > goto out; > } > - ret = fgetxattr(fd, name, value, size); > + ret = fgetxattr(rd_fd.fd, name, value, size); > saverr = ret == -1 ? errno : 0; > } else { > g_auto(TempFd) path_fd = TEMP_FD_INIT; > @@ -3153,10 +3161,6 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, > fuse_reply_xattr(req, ret); > } > out_free: > - if (fd >= 0) { > - close(fd); > - } > - > lo_inode_put(lo, &inode); > return; > > @@ -3176,7 +3180,6 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) > struct lo_inode *inode; > ssize_t ret; > int saverr; > - int fd = -1; > > inode = lo_inode(req, ino); > if (!inode) { > @@ -3200,12 +3203,14 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) > } > > if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { > - fd = lo_inode_open(lo, inode, O_RDONLY); > - if (fd < 0) { > - saverr = -fd; > + g_auto(TempFd) rd_fd = TEMP_FD_INIT; > + > + ret = lo_inode_open(lo, inode, O_RDONLY, &rd_fd); > + if (ret < 0) { > + saverr = -ret; > goto out; > } > - ret = flistxattr(fd, value, size); > + ret = flistxattr(rd_fd.fd, value, size); > saverr = ret == -1 ? errno : 0; > } else { > g_auto(TempFd) path_fd = TEMP_FD_INIT; > @@ -3294,10 +3299,6 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) > fuse_reply_xattr(req, ret); > } > out_free: > - if (fd >= 0) { > - close(fd); > - } > - > lo_inode_put(lo, &inode); > return; > > @@ -3312,14 +3313,14 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, > const char *value, size_t size, int flags, > uint32_t extra_flags) > { > - g_auto(TempFd) path_fd = TEMP_FD_INIT; > + g_auto(TempFd) path_fd = TEMP_FD_INIT; /* O_PATH fd */ > + g_auto(TempFd) rd_fd = TEMP_FD_INIT; /* O_RDONLY fd */ > const char *name; > char *mapped_name; > struct lo_data *lo = lo_data(req); > struct lo_inode *inode; > ssize_t ret; > int saverr; > - int fd = -1; > bool switched_creds = false; > bool cap_fsetid_dropped = false; > struct lo_cred old = {}; > @@ -3364,9 +3365,9 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, > * setxattr() on the link's filename there. > */ > if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { > - fd = lo_inode_open(lo, inode, O_RDONLY); > - if (fd < 0) { > - saverr = -fd; > + ret = lo_inode_open(lo, inode, O_RDONLY, &rd_fd); > + if (ret < 0) { > + saverr = -ret; > goto out; > } > } else { > @@ -3401,8 +3402,8 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, > } > switched_creds = true; > } > - if (fd >= 0) { > - ret = fsetxattr(fd, name, value, size, flags); > + if (rd_fd.fd >= 0) { > + ret = fsetxattr(rd_fd.fd, name, value, size, flags); > saverr = ret == -1 ? errno : 0; > } else { > char procname[64]; > @@ -3424,10 +3425,6 @@ out: > FCHDIR_NOFAIL(lo->root.fd); > } > > - if (fd >= 0) { > - close(fd); > - } > - > lo_inode_put(lo, &inode); > g_free(mapped_name); > fuse_reply_err(req, saverr); > @@ -3442,7 +3439,6 @@ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *in_name) > struct lo_inode *inode; > ssize_t ret; > int saverr; > - int fd = -1; > > if (block_xattr(lo, in_name)) { > fuse_reply_err(req, EOPNOTSUPP); > @@ -3478,12 +3474,14 @@ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *in_name) > name); > > if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { > - fd = lo_inode_open(lo, inode, O_RDONLY); > - if (fd < 0) { > - saverr = -fd; > + g_auto(TempFd) rd_fd = TEMP_FD_INIT; > + > + ret = lo_inode_open(lo, inode, O_RDONLY, &rd_fd); > + if (ret < 0) { > + saverr = -ret; > goto out; > } > - ret = fremovexattr(fd, name); > + ret = fremovexattr(rd_fd.fd, name); > saverr = ret == -1 ? errno : 0; > } else { > g_auto(TempFd) path_fd = TEMP_FD_INIT; > @@ -3502,10 +3500,6 @@ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *in_name) > } > > out: > - if (fd >= 0) { > - close(fd); > - } > - > lo_inode_put(lo, &inode); > g_free(mapped_name); > fuse_reply_err(req, saverr); > -- > 2.31.1 >
On 18.10.21 21:18, Vivek Goyal wrote: > On Thu, Sep 16, 2021 at 10:40:40AM +0200, Hanna Reitz wrote: >> Strictly speaking, this is not necessary, because lo_inode_open() will >> always return a new FD owned by the caller, so TempFd.owned will always >> be true. >> >> The auto-cleanup is nice, though. Also, we get a more unified interface >> where you always get a TempFd when you need an FD for an lo_inode >> (regardless of whether it is an O_PATH FD or a non-O_PATH FD). >> >> Signed-off-by: Hanna Reitz <hreitz@redhat.com> >> --- >> tools/virtiofsd/passthrough_ll.c | 156 +++++++++++++++---------------- >> 1 file changed, 75 insertions(+), 81 deletions(-) >> >> diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c >> index 3bf20b8659..d257eda129 100644 >> --- a/tools/virtiofsd/passthrough_ll.c >> +++ b/tools/virtiofsd/passthrough_ll.c >> @@ -293,10 +293,8 @@ static void temp_fd_clear(TempFd *temp_fd) >> /** >> * Return an owned fd from *temp_fd that will not be closed when >> * *temp_fd goes out of scope. >> - * >> - * (TODO: Remove __attribute__ once this is used.) >> */ >> -static __attribute__((unused)) int temp_fd_steal(TempFd *temp_fd) >> +static int temp_fd_steal(TempFd *temp_fd) >> { >> if (temp_fd->owned) { >> temp_fd->owned = false; >> @@ -309,10 +307,8 @@ static __attribute__((unused)) int temp_fd_steal(TempFd *temp_fd) >> /** >> * Create a borrowing copy of an existing TempFd. Note that *to is >> * only valid as long as *from is valid. >> - * >> - * (TODO: Remove __attribute__ once this is used.) >> */ >> -static __attribute__((unused)) void temp_fd_copy(const TempFd *from, TempFd *to) >> +static void temp_fd_copy(const TempFd *from, TempFd *to) >> { >> *to = (TempFd) { >> .fd = from->fd, >> @@ -689,9 +685,12 @@ static int lo_fd(fuse_req_t req, fuse_ino_t ino, TempFd *tfd) >> * when a malicious client opens special files such as block device nodes. >> * Symlink inodes are also rejected since symlinks must already have been >> * traversed on the client side. >> + * >> + * The fd is returned in tfd->fd. The return value is 0 on success and -errno >> + * otherwise. >> */ >> static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode, >> - int open_flags) >> + int open_flags, TempFd *tfd) >> { >> g_autofree char *fd_str = g_strdup_printf("%d", inode->fd); >> int fd; >> @@ -710,7 +709,13 @@ static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode, >> if (fd < 0) { >> return -errno; >> } >> - return fd; >> + >> + *tfd = (TempFd) { >> + .fd = fd, >> + .owned = true, >> + }; >> + >> + return 0; >> } >> >> static void lo_init(void *userdata, struct fuse_conn_info *conn) >> @@ -854,7 +859,8 @@ static int lo_fi_fd(fuse_req_t req, struct fuse_file_info *fi) >> static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, >> int valid, struct fuse_file_info *fi) >> { >> - g_auto(TempFd) path_fd = TEMP_FD_INIT; >> + g_auto(TempFd) path_fd = TEMP_FD_INIT; /* at least an O_PATH fd */ > What does atleast O_PATH fd mean? It means it might as well be an O_RDWR FD. When we open an O_RDWR FD, it’s pointless to open an O_PATH FD, too, because we can use the O_RDWR FD everywhere where we’d need an O_PATH FD. Hence in this case, we open rw_fd and copy it to path_fd. Users still use rw_fd and path_fd according to what they need. > >> + g_auto(TempFd) rw_fd = TEMP_FD_INIT; /* O_RDWR fd */ >> int saverr; >> char procname[64]; >> struct lo_data *lo = lo_data(req); >> @@ -868,7 +874,15 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, >> return; >> } >> >> - res = lo_inode_fd(inode, &path_fd); >> + if (!fi && (valid & FUSE_SET_ATTR_SIZE)) { >> + /* We need an O_RDWR FD for ftruncate() */ >> + res = lo_inode_open(lo, inode, O_RDWR, &rw_fd); >> + if (res >= 0) { >> + temp_fd_copy(&rw_fd, &path_fd); > I am lost here. If lo_inode_open() failed, why are we calling this > temp_fd_copy()? path_fd is not even a valid fd yet. We’re calling it on success. > Still beats me that why open rw_fd now instead of down in > FUSE_SET_ATTR_SIZE block. I think we had this discussion and you > had some reasons to move it up. Because it’s pointless overhead to open two FDs. Before file handles, getting the O_PATH FD was a trivial operation. If we needed an O_RDWR FD later, we’d open it later. No duplicate work involved. With file handles, getting the O_PATH FD may mean opening a new FD. Opening another FD from the same file handle, just with different flags, later on would be strange, because we could have just opened the FD as O_RDWR right from the start. Hanna
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index 3bf20b8659..d257eda129 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -293,10 +293,8 @@ static void temp_fd_clear(TempFd *temp_fd) /** * Return an owned fd from *temp_fd that will not be closed when * *temp_fd goes out of scope. - * - * (TODO: Remove __attribute__ once this is used.) */ -static __attribute__((unused)) int temp_fd_steal(TempFd *temp_fd) +static int temp_fd_steal(TempFd *temp_fd) { if (temp_fd->owned) { temp_fd->owned = false; @@ -309,10 +307,8 @@ static __attribute__((unused)) int temp_fd_steal(TempFd *temp_fd) /** * Create a borrowing copy of an existing TempFd. Note that *to is * only valid as long as *from is valid. - * - * (TODO: Remove __attribute__ once this is used.) */ -static __attribute__((unused)) void temp_fd_copy(const TempFd *from, TempFd *to) +static void temp_fd_copy(const TempFd *from, TempFd *to) { *to = (TempFd) { .fd = from->fd, @@ -689,9 +685,12 @@ static int lo_fd(fuse_req_t req, fuse_ino_t ino, TempFd *tfd) * when a malicious client opens special files such as block device nodes. * Symlink inodes are also rejected since symlinks must already have been * traversed on the client side. + * + * The fd is returned in tfd->fd. The return value is 0 on success and -errno + * otherwise. */ static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode, - int open_flags) + int open_flags, TempFd *tfd) { g_autofree char *fd_str = g_strdup_printf("%d", inode->fd); int fd; @@ -710,7 +709,13 @@ static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode, if (fd < 0) { return -errno; } - return fd; + + *tfd = (TempFd) { + .fd = fd, + .owned = true, + }; + + return 0; } static void lo_init(void *userdata, struct fuse_conn_info *conn) @@ -854,7 +859,8 @@ static int lo_fi_fd(fuse_req_t req, struct fuse_file_info *fi) static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int valid, struct fuse_file_info *fi) { - g_auto(TempFd) path_fd = TEMP_FD_INIT; + g_auto(TempFd) path_fd = TEMP_FD_INIT; /* at least an O_PATH fd */ + g_auto(TempFd) rw_fd = TEMP_FD_INIT; /* O_RDWR fd */ int saverr; char procname[64]; struct lo_data *lo = lo_data(req); @@ -868,7 +874,15 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, return; } - res = lo_inode_fd(inode, &path_fd); + if (!fi && (valid & FUSE_SET_ATTR_SIZE)) { + /* We need an O_RDWR FD for ftruncate() */ + res = lo_inode_open(lo, inode, O_RDWR, &rw_fd); + if (res >= 0) { + temp_fd_copy(&rw_fd, &path_fd); + } + } else { + res = lo_inode_fd(inode, &path_fd); + } if (res < 0) { saverr = -res; goto out_err; @@ -916,18 +930,12 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, if (fi) { truncfd = fd; } else { - truncfd = lo_inode_open(lo, inode, O_RDWR); - if (truncfd < 0) { - saverr = -truncfd; - goto out_err; - } + assert(rw_fd.fd >= 0); + truncfd = rw_fd.fd; } saverr = drop_security_capability(lo, truncfd); if (saverr) { - if (!fi) { - close(truncfd); - } goto out_err; } @@ -935,9 +943,6 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, res = drop_effective_cap("FSETID", &cap_fsetid_dropped); if (res != 0) { saverr = res; - if (!fi) { - close(truncfd); - } goto out_err; } } @@ -950,9 +955,6 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_FSETID\n"); } } - if (!fi) { - close(truncfd); - } if (res == -1) { goto out_err; } @@ -1840,11 +1842,13 @@ static struct lo_dirp *lo_dirp(fuse_req_t req, struct fuse_file_info *fi) static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { + g_auto(TempFd) rd_fd = TEMP_FD_INIT; int error = ENOMEM; struct lo_data *lo = lo_data(req); struct lo_inode *inode; struct lo_dirp *d = NULL; int fd; + int res; ssize_t fh; inode = lo_inode(req, ino); @@ -1858,14 +1862,16 @@ static void lo_opendir(fuse_req_t req, fuse_ino_t ino, goto out_err; } - fd = lo_inode_open(lo, inode, O_RDONLY); - if (fd < 0) { - error = -fd; + res = lo_inode_open(lo, inode, O_RDONLY, &rd_fd); + if (res < 0) { + error = -res; goto out_err; } + fd = temp_fd_steal(&rd_fd); d->dp = fdopendir(fd); if (d->dp == NULL) { + close(fd); goto out_errno; } @@ -1895,8 +1901,6 @@ out_err: if (d) { if (d->dp) { closedir(d->dp); - } else if (fd != -1) { - close(fd); } free(d); } @@ -2096,6 +2100,7 @@ static void update_open_flags(int writeback, int allow_direct_io, static int lo_do_open(struct lo_data *lo, struct lo_inode *inode, int existing_fd, struct fuse_file_info *fi) { + g_auto(TempFd) opened_fd = TEMP_FD_INIT; ssize_t fh; int fd = existing_fd; int err; @@ -2112,16 +2117,18 @@ static int lo_do_open(struct lo_data *lo, struct lo_inode *inode, } } - fd = lo_inode_open(lo, inode, fi->flags); + err = lo_inode_open(lo, inode, fi->flags, &opened_fd); if (cap_fsetid_dropped) { if (gain_effective_cap("FSETID")) { fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_FSETID\n"); } } - if (fd < 0) { - return -fd; + if (err < 0) { + return -err; } + fd = temp_fd_steal(&opened_fd); + if (fi->flags & (O_TRUNC)) { int err = drop_security_capability(lo, fd); if (err) { @@ -2231,8 +2238,9 @@ static struct lo_inode_plock *lookup_create_plock_ctx(struct lo_data *lo, uint64_t lock_owner, pid_t pid, int *err) { + g_auto(TempFd) rw_fd = TEMP_FD_INIT; struct lo_inode_plock *plock; - int fd; + int res; plock = g_hash_table_lookup(inode->posix_locks, GUINT_TO_POINTER(lock_owner)); @@ -2249,15 +2257,15 @@ static struct lo_inode_plock *lookup_create_plock_ctx(struct lo_data *lo, /* Open another instance of file which can be used for ofd locks. */ /* TODO: What if file is not writable? */ - fd = lo_inode_open(lo, inode, O_RDWR); - if (fd < 0) { - *err = -fd; + res = lo_inode_open(lo, inode, O_RDWR, &rw_fd); + if (res < 0) { + *err = -res; free(plock); return NULL; } plock->lock_owner = lock_owner; - plock->fd = fd; + plock->fd = temp_fd_steal(&rw_fd); g_hash_table_insert(inode->posix_locks, GUINT_TO_POINTER(plock->lock_owner), plock); return plock; @@ -2473,6 +2481,7 @@ static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) { + g_auto(TempFd) rw_fd = TEMP_FD_INIT; struct lo_inode *inode = lo_inode(req, ino); struct lo_data *lo = lo_data(req); int res; @@ -2487,11 +2496,12 @@ static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, } if (!fi) { - fd = lo_inode_open(lo, inode, O_RDWR); - if (fd < 0) { - res = -fd; + res = lo_inode_open(lo, inode, O_RDWR, &rw_fd); + if (res < 0) { + res = -res; goto out; } + fd = rw_fd.fd; } else { fd = lo_fi_fd(req, fi); } @@ -2501,9 +2511,6 @@ static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, } else { res = fsync(fd) == -1 ? errno : 0; } - if (!fi) { - close(fd); - } out: lo_inode_put(lo, &inode); fuse_reply_err(req, res); @@ -3065,7 +3072,6 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, struct lo_inode *inode; ssize_t ret; int saverr; - int fd = -1; if (block_xattr(lo, in_name)) { fuse_reply_err(req, EOPNOTSUPP); @@ -3117,12 +3123,14 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, * Otherwise, call fchdir() to avoid open(). */ if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { - fd = lo_inode_open(lo, inode, O_RDONLY); - if (fd < 0) { - saverr = -fd; + g_auto(TempFd) rd_fd = TEMP_FD_INIT; + + ret = lo_inode_open(lo, inode, O_RDONLY, &rd_fd); + if (ret < 0) { + saverr = -ret; goto out; } - ret = fgetxattr(fd, name, value, size); + ret = fgetxattr(rd_fd.fd, name, value, size); saverr = ret == -1 ? errno : 0; } else { g_auto(TempFd) path_fd = TEMP_FD_INIT; @@ -3153,10 +3161,6 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, fuse_reply_xattr(req, ret); } out_free: - if (fd >= 0) { - close(fd); - } - lo_inode_put(lo, &inode); return; @@ -3176,7 +3180,6 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) struct lo_inode *inode; ssize_t ret; int saverr; - int fd = -1; inode = lo_inode(req, ino); if (!inode) { @@ -3200,12 +3203,14 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) } if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { - fd = lo_inode_open(lo, inode, O_RDONLY); - if (fd < 0) { - saverr = -fd; + g_auto(TempFd) rd_fd = TEMP_FD_INIT; + + ret = lo_inode_open(lo, inode, O_RDONLY, &rd_fd); + if (ret < 0) { + saverr = -ret; goto out; } - ret = flistxattr(fd, value, size); + ret = flistxattr(rd_fd.fd, value, size); saverr = ret == -1 ? errno : 0; } else { g_auto(TempFd) path_fd = TEMP_FD_INIT; @@ -3294,10 +3299,6 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) fuse_reply_xattr(req, ret); } out_free: - if (fd >= 0) { - close(fd); - } - lo_inode_put(lo, &inode); return; @@ -3312,14 +3313,14 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, const char *value, size_t size, int flags, uint32_t extra_flags) { - g_auto(TempFd) path_fd = TEMP_FD_INIT; + g_auto(TempFd) path_fd = TEMP_FD_INIT; /* O_PATH fd */ + g_auto(TempFd) rd_fd = TEMP_FD_INIT; /* O_RDONLY fd */ const char *name; char *mapped_name; struct lo_data *lo = lo_data(req); struct lo_inode *inode; ssize_t ret; int saverr; - int fd = -1; bool switched_creds = false; bool cap_fsetid_dropped = false; struct lo_cred old = {}; @@ -3364,9 +3365,9 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, * setxattr() on the link's filename there. */ if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { - fd = lo_inode_open(lo, inode, O_RDONLY); - if (fd < 0) { - saverr = -fd; + ret = lo_inode_open(lo, inode, O_RDONLY, &rd_fd); + if (ret < 0) { + saverr = -ret; goto out; } } else { @@ -3401,8 +3402,8 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, } switched_creds = true; } - if (fd >= 0) { - ret = fsetxattr(fd, name, value, size, flags); + if (rd_fd.fd >= 0) { + ret = fsetxattr(rd_fd.fd, name, value, size, flags); saverr = ret == -1 ? errno : 0; } else { char procname[64]; @@ -3424,10 +3425,6 @@ out: FCHDIR_NOFAIL(lo->root.fd); } - if (fd >= 0) { - close(fd); - } - lo_inode_put(lo, &inode); g_free(mapped_name); fuse_reply_err(req, saverr); @@ -3442,7 +3439,6 @@ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *in_name) struct lo_inode *inode; ssize_t ret; int saverr; - int fd = -1; if (block_xattr(lo, in_name)) { fuse_reply_err(req, EOPNOTSUPP); @@ -3478,12 +3474,14 @@ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *in_name) name); if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { - fd = lo_inode_open(lo, inode, O_RDONLY); - if (fd < 0) { - saverr = -fd; + g_auto(TempFd) rd_fd = TEMP_FD_INIT; + + ret = lo_inode_open(lo, inode, O_RDONLY, &rd_fd); + if (ret < 0) { + saverr = -ret; goto out; } - ret = fremovexattr(fd, name); + ret = fremovexattr(rd_fd.fd, name); saverr = ret == -1 ? errno : 0; } else { g_auto(TempFd) path_fd = TEMP_FD_INIT; @@ -3502,10 +3500,6 @@ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *in_name) } out: - if (fd >= 0) { - close(fd); - } - lo_inode_put(lo, &inode); g_free(mapped_name); fuse_reply_err(req, saverr);
Strictly speaking, this is not necessary, because lo_inode_open() will always return a new FD owned by the caller, so TempFd.owned will always be true. The auto-cleanup is nice, though. Also, we get a more unified interface where you always get a TempFd when you need an FD for an lo_inode (regardless of whether it is an O_PATH FD or a non-O_PATH FD). Signed-off-by: Hanna Reitz <hreitz@redhat.com> --- tools/virtiofsd/passthrough_ll.c | 156 +++++++++++++++---------------- 1 file changed, 75 insertions(+), 81 deletions(-)