OSDN Git Service

ext4: remove never taken branch from ext4_ext_shift_path_extents()
[android-x86/kernel.git] / fs / namei.c
index d944f6d..db5fe86 100644 (file)
@@ -2384,22 +2384,17 @@ kern_path_mountpoint(int dfd, const char *name, struct path *path,
 }
 EXPORT_SYMBOL(kern_path_mountpoint);
 
-/*
- * It's inline, so penalty for filesystems that don't use sticky bit is
- * minimal.
- */
-static inline int check_sticky(struct inode *dir, struct inode *inode)
+int __check_sticky(struct inode *dir, struct inode *inode)
 {
        kuid_t fsuid = current_fsuid();
 
-       if (!(dir->i_mode & S_ISVTX))
-               return 0;
        if (uid_eq(inode->i_uid, fsuid))
                return 0;
        if (uid_eq(dir->i_uid, fsuid))
                return 0;
        return !capable_wrt_inode_uidgid(inode, CAP_FOWNER);
 }
+EXPORT_SYMBOL(__check_sticky);
 
 /*
  *     Check whether we can remove a link victim from directory dir, check
@@ -2502,7 +2497,7 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
        }
 
        mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
-       mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD);
+       mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT2);
        return NULL;
 }
 EXPORT_SYMBOL(lock_rename);
@@ -3159,7 +3154,8 @@ static int do_tmpfile(int dfd, struct filename *pathname,
        if (error)
                goto out2;
        audit_inode(pathname, nd->path.dentry, 0);
-       error = may_open(&nd->path, op->acc_mode, op->open_flag);
+       /* Don't check for other permissions, the inode was just created */
+       error = may_open(&nd->path, MAY_OPEN, op->open_flag);
        if (error)
                goto out2;
        file->f_path.mnt = nd->path.mnt;
@@ -4214,12 +4210,16 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
        bool should_retry = false;
        int error;
 
-       if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
+       if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
                return -EINVAL;
 
-       if ((flags & RENAME_NOREPLACE) && (flags & RENAME_EXCHANGE))
+       if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) &&
+           (flags & RENAME_EXCHANGE))
                return -EINVAL;
 
+       if ((flags & RENAME_WHITEOUT) && !capable(CAP_MKNOD))
+               return -EPERM;
+
 retry:
        from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags);
        if (IS_ERR(from)) {
@@ -4351,6 +4351,20 @@ SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newna
        return sys_renameat2(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
 }
 
+int vfs_whiteout(struct inode *dir, struct dentry *dentry)
+{
+       int error = may_create(dir, dentry);
+       if (error)
+               return error;
+
+       if (!dir->i_op->mknod)
+               return -EPERM;
+
+       return dir->i_op->mknod(dir, dentry,
+                               S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV);
+}
+EXPORT_SYMBOL(vfs_whiteout);
+
 int readlink_copy(char __user *buffer, int buflen, const char *link)
 {
        int len = PTR_ERR(link);