These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / fs / overlayfs / copy_up.c
index 84d693d..eff6319 100644 (file)
@@ -22,9 +22,9 @@
 
 int ovl_copy_xattr(struct dentry *old, struct dentry *new)
 {
-       ssize_t list_size, size;
-       char *buf, *name, *value;
-       int error;
+       ssize_t list_size, size, value_size = 0;
+       char *buf, *name, *value = NULL;
+       int uninitialized_var(error);
 
        if (!old->d_inode->i_op->getxattr ||
            !new->d_inode->i_op->getxattr)
@@ -41,29 +41,40 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
        if (!buf)
                return -ENOMEM;
 
-       error = -ENOMEM;
-       value = kmalloc(XATTR_SIZE_MAX, GFP_KERNEL);
-       if (!value)
-               goto out;
-
        list_size = vfs_listxattr(old, buf, list_size);
        if (list_size <= 0) {
                error = list_size;
-               goto out_free_value;
+               goto out;
        }
 
        for (name = buf; name < (buf + list_size); name += strlen(name) + 1) {
-               size = vfs_getxattr(old, name, value, XATTR_SIZE_MAX);
-               if (size <= 0) {
+retry:
+               size = vfs_getxattr(old, name, value, value_size);
+               if (size == -ERANGE)
+                       size = vfs_getxattr(old, name, NULL, 0);
+
+               if (size < 0) {
                        error = size;
-                       goto out_free_value;
+                       break;
+               }
+
+               if (size > value_size) {
+                       void *new;
+
+                       new = krealloc(value, size, GFP_KERNEL);
+                       if (!new) {
+                               error = -ENOMEM;
+                               break;
+                       }
+                       value = new;
+                       value_size = size;
+                       goto retry;
                }
+
                error = vfs_setxattr(new, name, value, size, 0);
                if (error)
-                       goto out_free_value;
+                       break;
        }
-
-out_free_value:
        kfree(value);
 out:
        kfree(buf);
@@ -81,11 +92,11 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
        if (len == 0)
                return 0;
 
-       old_file = ovl_path_open(old, O_RDONLY);
+       old_file = ovl_path_open(old, O_LARGEFILE | O_RDONLY);
        if (IS_ERR(old_file))
                return PTR_ERR(old_file);
 
-       new_file = ovl_path_open(new, O_WRONLY);
+       new_file = ovl_path_open(new, O_LARGEFILE | O_WRONLY);
        if (IS_ERR(new_file)) {
                error = PTR_ERR(new_file);
                goto out_fput;
@@ -195,8 +206,7 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
 
 static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
                              struct dentry *dentry, struct path *lowerpath,
-                             struct kstat *stat, struct iattr *attr,
-                             const char *link)
+                             struct kstat *stat, const char *link)
 {
        struct inode *wdir = workdir->d_inode;
        struct inode *udir = upperdir->d_inode;
@@ -240,8 +250,6 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
 
        mutex_lock(&newdentry->d_inode->i_mutex);
        err = ovl_set_attr(newdentry, stat);
-       if (!err && attr)
-               err = notify_change(newdentry, attr, NULL);
        mutex_unlock(&newdentry->d_inode->i_mutex);
        if (err)
                goto out_cleanup;
@@ -267,7 +275,7 @@ out:
 
 out_cleanup:
        ovl_cleanup(wdir, newdentry);
-       goto out;
+       goto out2;
 }
 
 /*
@@ -286,8 +294,7 @@ out_cleanup:
  * that point the file will have already been copied up anyway.
  */
 int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
-                   struct path *lowerpath, struct kstat *stat,
-                   struct iattr *attr)
+                   struct path *lowerpath, struct kstat *stat)
 {
        struct dentry *workdir = ovl_workdir(dentry);
        int err;
@@ -345,26 +352,19 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
        }
        upperdentry = ovl_dentry_upper(dentry);
        if (upperdentry) {
-               unlock_rename(workdir, upperdir);
+               /* Raced with another copy-up?  Nothing to do, then... */
                err = 0;
-               /* Raced with another copy-up?  Do the setattr here */
-               if (attr) {
-                       mutex_lock(&upperdentry->d_inode->i_mutex);
-                       err = notify_change(upperdentry, attr, NULL);
-                       mutex_unlock(&upperdentry->d_inode->i_mutex);
-               }
-               goto out_put_cred;
+               goto out_unlock;
        }
 
        err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath,
-                                stat, attr, link);
+                                stat, link);
        if (!err) {
                /* Restore timestamps on parent (best effort) */
                ovl_set_timestamps(upperdir, &pstat);
        }
 out_unlock:
        unlock_rename(workdir, upperdir);
-out_put_cred:
        revert_creds(old_cred);
        put_cred(override_cred);
 
@@ -406,7 +406,7 @@ int ovl_copy_up(struct dentry *dentry)
                ovl_path_lower(next, &lowerpath);
                err = vfs_getattr(&lowerpath, &stat);
                if (!err)
-                       err = ovl_copy_up_one(parent, next, &lowerpath, &stat, NULL);
+                       err = ovl_copy_up_one(parent, next, &lowerpath, &stat);
 
                dput(parent);
                dput(next);