cifs: call cifs_update_eof with i_lock held
authorJeff Layton <jlayton@redhat.com>
Fri, 23 Mar 2012 18:40:56 +0000 (14:40 -0400)
committerJeff Layton <jlayton@redhat.com>
Fri, 23 Mar 2012 18:40:56 +0000 (14:40 -0400)
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>
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/file.c

index d7e39b0..4ff6313 100644 (file)
@@ -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
index 5ec0b90..b63bf5f 100644 (file)
@@ -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)
index 58ac0f0..6883b08 100644 (file)
@@ -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)