Browse Source

Backport bug fixes from libfuse3

pull/1127/head
Antonio SJ Musumeci 2 years ago
parent
commit
7ed91c1668
  1. 126
      libfuse/lib/fuse.c
  2. 10
      libfuse/lib/fuse_lowlevel.c

126
libfuse/lib/fuse.c

@ -93,8 +93,6 @@ struct lock_queue_element
char **path2; char **path2;
struct node **wnode2; struct node **wnode2;
int err; int err;
bool first_locked : 1;
bool second_locked : 1;
bool done : 1; bool done : 1;
}; };
@ -973,25 +971,33 @@ try_get_path(struct fuse *f,
} }
static static
void
queue_element_unlock(struct fuse *f,
struct lock_queue_element *qe)
int
try_get_path2(struct fuse *f,
uint64_t nodeid1,
const char *name1,
uint64_t nodeid2,
const char *name2,
char **path1,
char **path2,
struct node **wnode1,
struct node **wnode2)
{ {
struct node *wnode;
int err;
if(qe->first_locked)
err = try_get_path(f,nodeid1,name1,path1,wnode1,true);
if(!err)
{ {
wnode = qe->wnode1 ? *qe->wnode1 : NULL;
unlock_path(f,qe->nodeid1,wnode,NULL);
qe->first_locked = false;
}
if(qe->second_locked)
err = try_get_path(f,nodeid2,name2,path2,wnode2,true);
if(err)
{ {
wnode = qe->wnode2 ? *qe->wnode2 : NULL;
unlock_path(f,qe->nodeid2,wnode,NULL);
qe->second_locked = false;
struct node *wn1 = wnode1 ? *wnode1 : NULL;
unlock_path(f,nodeid1,wn1,NULL);
free(*path1);
}
} }
return err;
} }
static static
@ -1000,7 +1006,6 @@ queue_element_wakeup(struct fuse *f,
struct lock_queue_element *qe) struct lock_queue_element *qe)
{ {
int err; int err;
bool first = (qe == f->lockq);
if(!qe->path1) if(!qe->path1)
{ {
@ -1011,46 +1016,34 @@ queue_element_wakeup(struct fuse *f,
return; return;
} }
if(!qe->first_locked)
{
err = try_get_path(f,qe->nodeid1,qe->name1,qe->path1,qe->wnode1,true);
if(!err)
qe->first_locked = true;
else if(err != -EAGAIN)
goto err_unlock;
}
if(qe->done)
return;
if(!qe->second_locked && qe->path2)
if(!qe->path2)
{ {
err = try_get_path(f,qe->nodeid2,qe->name2,qe->path2,qe->wnode2,true);
if(!err)
qe->second_locked = true;
else if(err != -EAGAIN)
goto err_unlock;
err = try_get_path(f,
qe->nodeid1,
qe->name1,
qe->path1,
qe->wnode1,
true);
} }
if(qe->first_locked && (qe->second_locked || !qe->path2))
else
{ {
err = 0;
goto done;
err = try_get_path2(f,
qe->nodeid1,
qe->name1,
qe->nodeid2,
qe->name2,
qe->path1,
qe->path2,
qe->wnode1,
qe->wnode2);
} }
/*
* Only let the first element be partially locked otherwise there could
* be a deadlock.
*
* But do allow the first element to be partially locked to prevent
* starvation.
*/
if(!first)
queue_element_unlock(f,qe);
/* keep trying */
if(err == -EAGAIN)
return; return;
err_unlock:
queue_element_unlock(f,qe);
done:
qe->err = err; qe->err = err;
qe->done = true; qe->done = true;
pthread_cond_signal(&qe->cond); pthread_cond_signal(&qe->cond);
@ -1074,8 +1067,6 @@ queue_path(struct fuse *f,
struct lock_queue_element **qp; struct lock_queue_element **qp;
qe->done = false; qe->done = false;
qe->first_locked = false;
qe->second_locked = false;
pthread_cond_init(&qe->cond,NULL); pthread_cond_init(&qe->cond,NULL);
qe->next = NULL; qe->next = NULL;
for(qp = &f->lockq; *qp != NULL; qp = &(*qp)->next); for(qp = &f->lockq; *qp != NULL; qp = &(*qp)->next);
@ -1169,37 +1160,6 @@ get_path_wrlock(struct fuse *f,
return get_path_common(f,nodeid,name,path,wnode); return get_path_common(f,nodeid,name,path,wnode);
} }
static
int
try_get_path2(struct fuse *f,
uint64_t nodeid1,
const char *name1,
uint64_t nodeid2,
const char *name2,
char **path1,
char **path2,
struct node **wnode1,
struct node **wnode2)
{
int err;
/* FIXME: locking two paths needs deadlock checking */
err = try_get_path(f,nodeid1,name1,path1,wnode1,true);
if(!err)
{
err = try_get_path(f,nodeid2,name2,path2,wnode2,true);
if(err)
{
struct node *wn1 = wnode1 ? *wnode1 : NULL;
unlock_path(f,nodeid1,wn1,NULL);
free(*path1);
}
}
return err;
}
static static
int int
get_path2(struct fuse *f, get_path2(struct fuse *f,
@ -3421,6 +3381,8 @@ fuse_lib_ioctl(fuse_req_t req,
arg->flags, arg->flags,
out_buf ?: (void *)in_buf, out_buf ?: (void *)in_buf,
&out_size); &out_size);
if(err < 0)
goto err;
fuse_reply_ioctl(req,err,out_buf,out_size); fuse_reply_ioctl(req,err,out_buf,out_size);
goto out; goto out;

10
libfuse/lib/fuse_lowlevel.c

@ -525,7 +525,7 @@ fuse_send_data_iov(struct fuse_ll *f,
struct fuse_ll_pipe *llp; struct fuse_ll_pipe *llp;
int splice_flags; int splice_flags;
size_t pipesize; size_t pipesize;
size_t total_fd_size;
size_t total_buf_size;
size_t idx; size_t idx;
size_t headerlen; size_t headerlen;
struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len); struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
@ -536,18 +536,18 @@ fuse_send_data_iov(struct fuse_ll *f,
if(flags & FUSE_BUF_NO_SPLICE) if(flags & FUSE_BUF_NO_SPLICE)
goto fallback; goto fallback;
total_fd_size = 0;
total_buf_size = 0;
for (idx = buf->idx; idx < buf->count; idx++) for (idx = buf->idx; idx < buf->count; idx++)
{ {
if(buf->buf[idx].flags & FUSE_BUF_IS_FD) if(buf->buf[idx].flags & FUSE_BUF_IS_FD)
{ {
total_fd_size = buf->buf[idx].size;
total_buf_size += buf->buf[idx].size;
if(idx == buf->idx) if(idx == buf->idx)
total_fd_size -= buf->off;
total_buf_size -= buf->off;
} }
} }
if(total_fd_size < 2 * pagesize)
if(total_buf_size < 2 * pagesize)
goto fallback; goto fallback;
if(f->conn.proto_minor < 14 || !(f->conn.want & FUSE_CAP_SPLICE_WRITE)) if(f->conn.proto_minor < 14 || !(f->conn.want & FUSE_CAP_SPLICE_WRITE))

Loading…
Cancel
Save