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 <jlayton@redhat.com>
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 @@
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 @@
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 @@
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 @@
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 @@
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)