From 597b027f694481ffeebcffe634c24b807198d46c Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 23 Mar 2012 14:40:56 -0400 Subject: cifs: call cifs_update_eof with i_lock held cifs_update_eof has the potential to be racy if multiple threads are trying to modify it at the same time. Protect modifications of the server_eof value with the inode->i_lock. Signed-off-by: Jeff Layton --- fs/cifs/cifsglob.h | 2 +- fs/cifs/cifssmb.c | 2 ++ fs/cifs/file.c | 9 ++++++++- 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d7e39b0..4ff6313 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -626,7 +626,7 @@ struct cifsInodeInfo { bool delete_pending; /* DELETE_ON_CLOSE is set */ bool invalid_mapping; /* pagecache is invalid */ unsigned long time; /* jiffies of last update of inode */ - u64 server_eof; /* current file size on server */ + u64 server_eof; /* current file size on server -- protected by i_lock */ u64 uniqueid; /* server inode number */ u64 createtime; /* creation time on server */ #ifdef CONFIG_CIFS_FSCACHE diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 5ec0b90..b63bf5f 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2044,7 +2044,9 @@ cifs_writev_complete(struct work_struct *work) int i = 0; if (wdata->result == 0) { + spin_lock(&inode->i_lock); cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes); + spin_unlock(&inode->i_lock); cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink), wdata->bytes); } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 58ac0f0..6883b08 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1399,7 +1399,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) return rc; } -/* update the file size (if needed) after a write */ +/* + * update the file size (if needed) after a write. Should be called with + * the inode->i_lock held + */ void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, unsigned int bytes_written) @@ -1471,7 +1474,9 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid, return rc; } } else { + spin_lock(&dentry->d_inode->i_lock); cifs_update_eof(cifsi, *poffset, bytes_written); + spin_unlock(&dentry->d_inode->i_lock); *poffset += bytes_written; } } @@ -2197,7 +2202,9 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, if (written) { len -= written; total_written += written; + spin_lock(&inode->i_lock); cifs_update_eof(CIFS_I(inode), *poffset, written); + spin_unlock(&inode->i_lock); *poffset += written; } else if (rc < 0) { if (!total_written) -- cgit v1.1