X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=fs%2Foverlayfs%2Finode.c;h=32ae8b49a72c8cc2e3b9bc368860a154f13202ca;hb=58ed4e70f253d80ed72faba7873dc11603b398bc;hp=1dbeab6cf96e54c7e43cf040ef3d909ce6fe2071;hpb=9a949a98596c45763299158b9018f3491e3cbf99;p=cascardo%2Flinux.git diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 1dbeab6cf96e..32ae8b49a72c 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -59,16 +59,40 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr) if (err) goto out; + if (attr->ia_valid & ATTR_SIZE) { + struct inode *realinode = d_inode(ovl_dentry_real(dentry)); + + err = -ETXTBSY; + if (atomic_read(&realinode->i_writecount) < 0) + goto out_drop_write; + } + err = ovl_copy_up(dentry); if (!err) { + struct inode *winode = NULL; + upperdentry = ovl_dentry_upper(dentry); + if (attr->ia_valid & ATTR_SIZE) { + winode = d_inode(upperdentry); + err = get_write_access(winode); + if (err) + goto out_drop_write; + } + + if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) + attr->ia_valid &= ~ATTR_MODE; + inode_lock(upperdentry->d_inode); err = notify_change(upperdentry, attr, NULL); if (!err) ovl_copyattr(upperdentry->d_inode, dentry->d_inode); inode_unlock(upperdentry->d_inode); + + if (winode) + put_write_access(winode); } +out_drop_write: ovl_drop_write(dentry); out: return err; @@ -85,31 +109,12 @@ static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry, int ovl_permission(struct inode *inode, int mask) { - struct ovl_entry *oe; - struct dentry *alias = NULL; - struct inode *realinode; - struct dentry *realdentry; + struct ovl_entry *oe = inode->i_private; bool is_upper; + struct dentry *realdentry = ovl_entry_real(oe, &is_upper); + struct inode *realinode; int err; - if (S_ISDIR(inode->i_mode)) { - oe = inode->i_private; - } else if (mask & MAY_NOT_BLOCK) { - return -ECHILD; - } else { - /* - * For non-directories find an alias and get the info - * from there. - */ - alias = d_find_any_alias(inode); - if (WARN_ON(!alias)) - return -ENOENT; - - oe = alias->d_fsdata; - } - - realdentry = ovl_entry_real(oe, &is_upper); - if (ovl_is_default_permissions(inode)) { struct kstat stat; struct path realpath = { .dentry = realdentry }; @@ -134,11 +139,10 @@ int ovl_permission(struct inode *inode, int mask) } /* Careful in RCU walk mode */ - realinode = ACCESS_ONCE(realdentry->d_inode); + realinode = d_inode_rcu(realdentry); if (!realinode) { WARN_ON(!(mask & MAY_NOT_BLOCK)); - err = -ENOENT; - goto out_dput; + return -ENOENT; } if (mask & MAY_WRITE) { @@ -157,16 +161,12 @@ int ovl_permission(struct inode *inode, int mask) * constructed return EROFS to prevent modification of * upper layer. */ - err = -EROFS; if (is_upper && !IS_RDONLY(inode) && IS_RDONLY(realinode) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) - goto out_dput; + return -EROFS; } - err = __inode_permission(realinode, mask); -out_dput: - dput(alias); - return err; + return __inode_permission(realinode, mask); } static const char *ovl_get_link(struct dentry *dentry, @@ -325,36 +325,25 @@ static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type, return true; } -struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags) +int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags) { - int err; + int err = 0; struct path realpath; enum ovl_path_type type; - if (d_is_dir(dentry)) - return d_backing_inode(dentry); - type = ovl_path_real(dentry, &realpath); if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) { err = ovl_want_write(dentry); - if (err) - return ERR_PTR(err); - - if (file_flags & O_TRUNC) - err = ovl_copy_up_truncate(dentry); - else - err = ovl_copy_up(dentry); - ovl_drop_write(dentry); - if (err) - return ERR_PTR(err); - - ovl_path_upper(dentry, &realpath); + if (!err) { + if (file_flags & O_TRUNC) + err = ovl_copy_up_truncate(dentry); + else + err = ovl_copy_up(dentry); + ovl_drop_write(dentry); + } } - if (realpath.dentry->d_flags & DCACHE_OP_SELECT_INODE) - return realpath.dentry->d_op->d_select_inode(realpath.dentry, file_flags); - - return d_backing_inode(realpath.dentry); + return err; } static const struct inode_operations ovl_file_inode_operations = { @@ -387,15 +376,14 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, if (!inode) return NULL; - mode &= S_IFMT; - inode->i_ino = get_next_ino(); inode->i_mode = mode; inode->i_flags |= S_NOATIME | S_NOCMTIME; + inode->i_private = oe; + mode &= S_IFMT; switch (mode) { case S_IFDIR: - inode->i_private = oe; inode->i_op = &ovl_dir_inode_operations; inode->i_fop = &ovl_dir_operations; break;