Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 95268
b: refs/heads/master
c: 3be5a52
h: refs/heads/master
v: v3
  • Loading branch information
Miklos Szeredi authored and Linus Torvalds committed Apr 30, 2008
1 parent 0be220f commit 1c3716a
Show file tree
Hide file tree
Showing 6 changed files with 482 additions and 30 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b88473f73e6d7b6af9cfc4ecc349d82c75d9a6af
refs/heads/master: 3be5a52b30aa5cf9d795b7634f728f612197b1c4
19 changes: 19 additions & 0 deletions trunk/fs/fuse/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ struct fuse_req *fuse_request_alloc(void)
return req;
}

struct fuse_req *fuse_request_alloc_nofs(void)
{
struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_NOFS);
if (req)
fuse_request_init(req);
return req;
}

void fuse_request_free(struct fuse_req *req)
{
kmem_cache_free(fuse_req_cachep, req);
Expand Down Expand Up @@ -429,6 +437,17 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
request_send_nowait(fc, req);
}

/*
* Called under fc->lock
*
* fc->connected must have been checked previously
*/
void request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req)
{
req->isreply = 1;
request_send_nowait_locked(fc, req);
}

/*
* Lock the request. Up to the next unlock_request() there mustn't be
* anything that could cause a page-fault. If the request was already
Expand Down
84 changes: 81 additions & 3 deletions trunk/fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,50 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
}
}

/*
* Prevent concurrent writepages on inode
*
* This is done by adding a negative bias to the inode write counter
* and waiting for all pending writes to finish.
*/
void fuse_set_nowrite(struct inode *inode)
{
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);

BUG_ON(!mutex_is_locked(&inode->i_mutex));

spin_lock(&fc->lock);
BUG_ON(fi->writectr < 0);
fi->writectr += FUSE_NOWRITE;
spin_unlock(&fc->lock);
wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE);
}

/*
* Allow writepages on inode
*
* Remove the bias from the writecounter and send any queued
* writepages.
*/
static void __fuse_release_nowrite(struct inode *inode)
{
struct fuse_inode *fi = get_fuse_inode(inode);

BUG_ON(fi->writectr != FUSE_NOWRITE);
fi->writectr = 0;
fuse_flush_writepages(inode);
}

void fuse_release_nowrite(struct inode *inode)
{
struct fuse_conn *fc = get_fuse_conn(inode);

spin_lock(&fc->lock);
__fuse_release_nowrite(inode);
spin_unlock(&fc->lock);
}

/*
* Set attributes, and at the same time refresh them.
*
Expand All @@ -1122,6 +1166,8 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
struct fuse_req *req;
struct fuse_setattr_in inarg;
struct fuse_attr_out outarg;
bool is_truncate = false;
loff_t oldsize;
int err;

if (!fuse_allow_task(fc, current))
Expand All @@ -1145,12 +1191,16 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
is_truncate = true;
}

req = fuse_get_req(fc);
if (IS_ERR(req))
return PTR_ERR(req);

if (is_truncate)
fuse_set_nowrite(inode);

memset(&inarg, 0, sizeof(inarg));
memset(&outarg, 0, sizeof(outarg));
iattr_to_fattr(attr, &inarg);
Expand Down Expand Up @@ -1181,16 +1231,44 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
if (err) {
if (err == -EINTR)
fuse_invalidate_attr(inode);
return err;
goto error;
}

if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
make_bad_inode(inode);
return -EIO;
err = -EIO;
goto error;
}

spin_lock(&fc->lock);
fuse_change_attributes_common(inode, &outarg.attr,
attr_timeout(&outarg));
oldsize = inode->i_size;
i_size_write(inode, outarg.attr.size);

if (is_truncate) {
/* NOTE: this may release/reacquire fc->lock */
__fuse_release_nowrite(inode);
}
spin_unlock(&fc->lock);

/*
* Only call invalidate_inode_pages2() after removing
* FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock.
*/
if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {
if (outarg.attr.size < oldsize)
fuse_truncate(inode->i_mapping, outarg.attr.size);
invalidate_inode_pages2(inode->i_mapping);
}

fuse_change_attributes(inode, &outarg.attr, attr_timeout(&outarg), 0);
return 0;

error:
if (is_truncate)
fuse_release_nowrite(inode);

return err;
}

static int fuse_setattr(struct dentry *entry, struct iattr *attr)
Expand Down
Loading

0 comments on commit 1c3716a

Please sign in to comment.