Merge remote-tracking branch 'ovl/misc' into work.misc

This commit is contained in:
Al Viro 2016-10-08 11:00:01 -04:00
commit f334bcd94b
25 changed files with 170 additions and 101 deletions

View File

@ -202,6 +202,21 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
return -EPERM; return -EPERM;
} }
/*
* If utimes(2) and friends are called with times == NULL (or both
* times are UTIME_NOW), then we need to check for write permission
*/
if (ia_valid & ATTR_TOUCH) {
if (IS_IMMUTABLE(inode))
return -EPERM;
if (!inode_owner_or_capable(inode)) {
error = inode_permission(inode, MAY_WRITE);
if (error)
return error;
}
}
if ((ia_valid & ATTR_MODE)) { if ((ia_valid & ATTR_MODE)) {
umode_t amode = attr->ia_mode; umode_t amode = attr->ia_mode;
/* Flag setting protected by i_mutex */ /* Flag setting protected by i_mutex */

View File

@ -3161,7 +3161,6 @@ int btrfs_prealloc_file_range_trans(struct inode *inode,
struct btrfs_trans_handle *trans, int mode, struct btrfs_trans_handle *trans, int mode,
u64 start, u64 num_bytes, u64 min_size, u64 start, u64 num_bytes, u64 min_size,
loff_t actual_len, u64 *alloc_hint); loff_t actual_len, u64 *alloc_hint);
int btrfs_inode_check_errors(struct inode *inode);
extern const struct dentry_operations btrfs_dentry_operations; extern const struct dentry_operations btrfs_dentry_operations;
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
void btrfs_test_inode_set_ops(struct inode *inode); void btrfs_test_inode_set_ops(struct inode *inode);

View File

@ -2040,7 +2040,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
* flags for any errors that might have happened while doing * flags for any errors that might have happened while doing
* writeback of file data. * writeback of file data.
*/ */
ret = btrfs_inode_check_errors(inode); ret = filemap_check_errors(inode->i_mapping);
inode_unlock(inode); inode_unlock(inode);
goto out; goto out;
} }

View File

@ -10543,21 +10543,6 @@ static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
} }
/* Inspired by filemap_check_errors() */
int btrfs_inode_check_errors(struct inode *inode)
{
int ret = 0;
if (test_bit(AS_ENOSPC, &inode->i_mapping->flags) &&
test_and_clear_bit(AS_ENOSPC, &inode->i_mapping->flags))
ret = -ENOSPC;
if (test_bit(AS_EIO, &inode->i_mapping->flags) &&
test_and_clear_bit(AS_EIO, &inode->i_mapping->flags))
ret = -EIO;
return ret;
}
static const struct inode_operations btrfs_dir_inode_operations = { static const struct inode_operations btrfs_dir_inode_operations = {
.getattr = btrfs_getattr, .getattr = btrfs_getattr,
.lookup = btrfs_lookup, .lookup = btrfs_lookup,

View File

@ -3961,7 +3961,7 @@ static int wait_ordered_extents(struct btrfs_trans_handle *trans,
* i_mapping flags, so that the next fsync won't get * i_mapping flags, so that the next fsync won't get
* an outdated io error too. * an outdated io error too.
*/ */
btrfs_inode_check_errors(inode); filemap_check_errors(inode->i_mapping);
*ordered_io_error = true; *ordered_io_error = true;
break; break;
} }
@ -4198,7 +4198,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
* without writing to the log tree and the fsync must report the * without writing to the log tree and the fsync must report the
* file data write error and not commit the current transaction. * file data write error and not commit the current transaction.
*/ */
ret = btrfs_inode_check_errors(inode); ret = filemap_check_errors(inode->i_mapping);
if (ret) if (ret)
ctx->io_err = ret; ctx->io_err = ret;
process: process:

View File

@ -41,6 +41,16 @@ cifs_uniqueid_to_ino_t(u64 fileid)
} }
static inline void cifs_set_time(struct dentry *dentry, unsigned long time)
{
dentry->d_fsdata = (void *) time;
}
static inline unsigned long cifs_get_time(struct dentry *dentry)
{
return (unsigned long) dentry->d_fsdata;
}
extern struct file_system_type cifs_fs_type; extern struct file_system_type cifs_fs_type;
extern const struct address_space_operations cifs_addr_ops; extern const struct address_space_operations cifs_addr_ops;
extern const struct address_space_operations cifs_addr_ops_smallbuf; extern const struct address_space_operations cifs_addr_ops_smallbuf;

View File

@ -40,7 +40,7 @@ renew_parental_timestamps(struct dentry *direntry)
/* BB check if there is a way to get the kernel to do this or if we /* BB check if there is a way to get the kernel to do this or if we
really need this */ really need this */
do { do {
direntry->d_time = jiffies; cifs_set_time(direntry, jiffies);
direntry = direntry->d_parent; direntry = direntry->d_parent;
} while (!IS_ROOT(direntry)); } while (!IS_ROOT(direntry));
} }
@ -802,7 +802,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
} else if (rc == -ENOENT) { } else if (rc == -ENOENT) {
rc = 0; rc = 0;
direntry->d_time = jiffies; cifs_set_time(direntry, jiffies);
d_add(direntry, NULL); d_add(direntry, NULL);
/* if it was once a directory (but how can we tell?) we could do /* if it was once a directory (but how can we tell?) we could do
shrink_dcache_parent(direntry); */ shrink_dcache_parent(direntry); */
@ -862,7 +862,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
return 0; return 0;
if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled) if (time_after(jiffies, cifs_get_time(direntry) + HZ) || !lookupCacheEnabled)
return 0; return 0;
return 1; return 1;

View File

@ -1951,7 +1951,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
cifs_dbg(FYI, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld\n", cifs_dbg(FYI, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld\n",
full_path, inode, inode->i_count.counter, full_path, inode, inode->i_count.counter,
dentry, dentry->d_time, jiffies); dentry, cifs_get_time(dentry), jiffies);
if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);

View File

@ -1513,7 +1513,7 @@ int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
{ {
pgoff_t index = 0, end = ULONG_MAX; pgoff_t index = 0, end = ULONG_MAX;
struct pagevec pvec; struct pagevec pvec;
int ret2 = 0, ret = 0; int ret2, ret = 0;
pagevec_init(&pvec, 0); pagevec_init(&pvec, 0);
@ -1542,10 +1542,7 @@ int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
cond_resched(); cond_resched();
} }
if (unlikely(test_and_clear_bit(AS_ENOSPC, &NODE_MAPPING(sbi)->flags))) ret2 = filemap_check_errors(NODE_MAPPING(sbi));
ret2 = -ENOSPC;
if (unlikely(test_and_clear_bit(AS_EIO, &NODE_MAPPING(sbi)->flags)))
ret2 = -EIO;
if (!ret) if (!ret)
ret = ret2; ret = ret2;
return ret; return ret;

View File

@ -21,6 +21,17 @@
#include <linux/namei.h> #include <linux/namei.h>
#include "fat.h" #include "fat.h"
static inline unsigned long vfat_d_version(struct dentry *dentry)
{
return (unsigned long) dentry->d_fsdata;
}
static inline void vfat_d_version_set(struct dentry *dentry,
unsigned long version)
{
dentry->d_fsdata = (void *) version;
}
/* /*
* If new entry was created in the parent, it could create the 8.3 * If new entry was created in the parent, it could create the 8.3
* alias (the shortname of logname). So, the parent may have the * alias (the shortname of logname). So, the parent may have the
@ -33,7 +44,7 @@ static int vfat_revalidate_shortname(struct dentry *dentry)
{ {
int ret = 1; int ret = 1;
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
if (dentry->d_time != d_inode(dentry->d_parent)->i_version) if (vfat_d_version(dentry) != d_inode(dentry->d_parent)->i_version)
ret = 0; ret = 0;
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
return ret; return ret;
@ -759,7 +770,7 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
out: out:
mutex_unlock(&MSDOS_SB(sb)->s_lock); mutex_unlock(&MSDOS_SB(sb)->s_lock);
if (!inode) if (!inode)
dentry->d_time = dir->i_version; vfat_d_version_set(dentry, dir->i_version);
return d_splice_alias(inode, dentry); return d_splice_alias(inode, dentry);
error: error:
mutex_unlock(&MSDOS_SB(sb)->s_lock); mutex_unlock(&MSDOS_SB(sb)->s_lock);
@ -823,7 +834,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
clear_nlink(inode); clear_nlink(inode);
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode); fat_detach(inode);
dentry->d_time = dir->i_version; vfat_d_version_set(dentry, dir->i_version);
out: out:
mutex_unlock(&MSDOS_SB(sb)->s_lock); mutex_unlock(&MSDOS_SB(sb)->s_lock);
@ -849,7 +860,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry)
clear_nlink(inode); clear_nlink(inode);
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode); fat_detach(inode);
dentry->d_time = dir->i_version; vfat_d_version_set(dentry, dir->i_version);
out: out:
mutex_unlock(&MSDOS_SB(sb)->s_lock); mutex_unlock(&MSDOS_SB(sb)->s_lock);

View File

@ -1562,17 +1562,37 @@ sector_t bmap(struct inode *inode, sector_t block)
} }
EXPORT_SYMBOL(bmap); EXPORT_SYMBOL(bmap);
/*
* Update times in overlayed inode from underlying real inode
*/
static void update_ovl_inode_times(struct dentry *dentry, struct inode *inode,
bool rcu)
{
if (!rcu) {
struct inode *realinode = d_real_inode(dentry);
if (unlikely(inode != realinode) &&
(!timespec_equal(&inode->i_mtime, &realinode->i_mtime) ||
!timespec_equal(&inode->i_ctime, &realinode->i_ctime))) {
inode->i_mtime = realinode->i_mtime;
inode->i_ctime = realinode->i_ctime;
}
}
}
/* /*
* With relative atime, only update atime if the previous atime is * With relative atime, only update atime if the previous atime is
* earlier than either the ctime or mtime or if at least a day has * earlier than either the ctime or mtime or if at least a day has
* passed since the last atime update. * passed since the last atime update.
*/ */
static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, static int relatime_need_update(const struct path *path, struct inode *inode,
struct timespec now) struct timespec now, bool rcu)
{ {
if (!(mnt->mnt_flags & MNT_RELATIME)) if (!(path->mnt->mnt_flags & MNT_RELATIME))
return 1; return 1;
update_ovl_inode_times(path->dentry, inode, rcu);
/* /*
* Is mtime younger than atime? If yes, update atime: * Is mtime younger than atime? If yes, update atime:
*/ */
@ -1639,7 +1659,8 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
* This function automatically handles read only file systems and media, * This function automatically handles read only file systems and media,
* as well as the "noatime" flag and inode specific "noatime" markers. * as well as the "noatime" flag and inode specific "noatime" markers.
*/ */
bool atime_needs_update(const struct path *path, struct inode *inode) bool __atime_needs_update(const struct path *path, struct inode *inode,
bool rcu)
{ {
struct vfsmount *mnt = path->mnt; struct vfsmount *mnt = path->mnt;
struct timespec now; struct timespec now;
@ -1665,7 +1686,7 @@ bool atime_needs_update(const struct path *path, struct inode *inode)
now = current_fs_time(inode->i_sb); now = current_fs_time(inode->i_sb);
if (!relatime_need_update(mnt, inode, now)) if (!relatime_need_update(path, inode, now, rcu))
return false; return false;
if (timespec_equal(&inode->i_atime, &now)) if (timespec_equal(&inode->i_atime, &now))
@ -1680,7 +1701,7 @@ void touch_atime(const struct path *path)
struct inode *inode = d_inode(path->dentry); struct inode *inode = d_inode(path->dentry);
struct timespec now; struct timespec now;
if (!atime_needs_update(path, inode)) if (!__atime_needs_update(path, inode, false))
return; return;
if (!sb_start_write_trylock(inode->i_sb)) if (!sb_start_write_trylock(inode->i_sb))

View File

@ -120,6 +120,15 @@ extern long prune_icache_sb(struct super_block *sb, struct shrink_control *sc);
extern void inode_add_lru(struct inode *inode); extern void inode_add_lru(struct inode *inode);
extern int dentry_needs_remove_privs(struct dentry *dentry); extern int dentry_needs_remove_privs(struct dentry *dentry);
extern bool __atime_needs_update(const struct path *, struct inode *, bool);
static inline bool atime_needs_update_rcu(const struct path *path,
struct inode *inode)
{
return __atime_needs_update(path, inode, true);
}
extern bool atime_needs_update_rcu(const struct path *, struct inode *);
/* /*
* fs-writeback.c * fs-writeback.c
*/ */

View File

@ -139,6 +139,11 @@
#define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT)) #define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT))
#define IS_OFDLCK(fl) (fl->fl_flags & FL_OFDLCK) #define IS_OFDLCK(fl) (fl->fl_flags & FL_OFDLCK)
static inline bool is_remote_lock(struct file *filp)
{
return likely(!(filp->f_path.dentry->d_sb->s_flags & MS_NOREMOTELOCK));
}
static bool lease_breaking(struct file_lock *fl) static bool lease_breaking(struct file_lock *fl)
{ {
return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING); return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
@ -791,7 +796,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
{ {
struct file_lock *cfl; struct file_lock *cfl;
struct file_lock_context *ctx; struct file_lock_context *ctx;
struct inode *inode = file_inode(filp); struct inode *inode = locks_inode(filp);
ctx = smp_load_acquire(&inode->i_flctx); ctx = smp_load_acquire(&inode->i_flctx);
if (!ctx || list_empty_careful(&ctx->flc_posix)) { if (!ctx || list_empty_careful(&ctx->flc_posix)) {
@ -1192,7 +1197,7 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,
int posix_lock_file(struct file *filp, struct file_lock *fl, int posix_lock_file(struct file *filp, struct file_lock *fl,
struct file_lock *conflock) struct file_lock *conflock)
{ {
return posix_lock_inode(file_inode(filp), fl, conflock); return posix_lock_inode(locks_inode(filp), fl, conflock);
} }
EXPORT_SYMBOL(posix_lock_file); EXPORT_SYMBOL(posix_lock_file);
@ -1232,7 +1237,7 @@ static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
int locks_mandatory_locked(struct file *file) int locks_mandatory_locked(struct file *file)
{ {
int ret; int ret;
struct inode *inode = file_inode(file); struct inode *inode = locks_inode(file);
struct file_lock_context *ctx; struct file_lock_context *ctx;
struct file_lock *fl; struct file_lock *fl;
@ -1572,7 +1577,7 @@ EXPORT_SYMBOL(lease_get_mtime);
int fcntl_getlease(struct file *filp) int fcntl_getlease(struct file *filp)
{ {
struct file_lock *fl; struct file_lock *fl;
struct inode *inode = file_inode(filp); struct inode *inode = locks_inode(filp);
struct file_lock_context *ctx; struct file_lock_context *ctx;
int type = F_UNLCK; int type = F_UNLCK;
LIST_HEAD(dispose); LIST_HEAD(dispose);
@ -1580,7 +1585,7 @@ int fcntl_getlease(struct file *filp)
ctx = smp_load_acquire(&inode->i_flctx); ctx = smp_load_acquire(&inode->i_flctx);
if (ctx && !list_empty_careful(&ctx->flc_lease)) { if (ctx && !list_empty_careful(&ctx->flc_lease)) {
spin_lock(&ctx->flc_lock); spin_lock(&ctx->flc_lock);
time_out_leases(file_inode(filp), &dispose); time_out_leases(inode, &dispose);
list_for_each_entry(fl, &ctx->flc_lease, fl_list) { list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
if (fl->fl_file != filp) if (fl->fl_file != filp)
continue; continue;
@ -1613,7 +1618,8 @@ check_conflicting_open(const struct dentry *dentry, const long arg, int flags)
if (flags & FL_LAYOUT) if (flags & FL_LAYOUT)
return 0; return 0;
if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) if ((arg == F_RDLCK) &&
(atomic_read(&d_real_inode(dentry)->i_writecount) > 0))
return -EAGAIN; return -EAGAIN;
if ((arg == F_WRLCK) && ((d_count(dentry) > 1) || if ((arg == F_WRLCK) && ((d_count(dentry) > 1) ||
@ -1628,7 +1634,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr
{ {
struct file_lock *fl, *my_fl = NULL, *lease; struct file_lock *fl, *my_fl = NULL, *lease;
struct dentry *dentry = filp->f_path.dentry; struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = file_inode(filp); struct inode *inode = dentry->d_inode;
struct file_lock_context *ctx; struct file_lock_context *ctx;
bool is_deleg = (*flp)->fl_flags & FL_DELEG; bool is_deleg = (*flp)->fl_flags & FL_DELEG;
int error; int error;
@ -1742,7 +1748,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
{ {
int error = -EAGAIN; int error = -EAGAIN;
struct file_lock *fl, *victim = NULL; struct file_lock *fl, *victim = NULL;
struct inode *inode = file_inode(filp); struct inode *inode = locks_inode(filp);
struct file_lock_context *ctx; struct file_lock_context *ctx;
LIST_HEAD(dispose); LIST_HEAD(dispose);
@ -1782,7 +1788,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
int generic_setlease(struct file *filp, long arg, struct file_lock **flp, int generic_setlease(struct file *filp, long arg, struct file_lock **flp,
void **priv) void **priv)
{ {
struct inode *inode = file_inode(filp); struct inode *inode = locks_inode(filp);
int error; int error;
if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE)) if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE))
@ -1830,7 +1836,7 @@ EXPORT_SYMBOL(generic_setlease);
int int
vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv) vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv)
{ {
if (filp->f_op->setlease) if (filp->f_op->setlease && is_remote_lock(filp))
return filp->f_op->setlease(filp, arg, lease, priv); return filp->f_op->setlease(filp, arg, lease, priv);
else else
return generic_setlease(filp, arg, lease, priv); return generic_setlease(filp, arg, lease, priv);
@ -1979,7 +1985,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
if (error) if (error)
goto out_free; goto out_free;
if (f.file->f_op->flock) if (f.file->f_op->flock && is_remote_lock(f.file))
error = f.file->f_op->flock(f.file, error = f.file->f_op->flock(f.file,
(can_sleep) ? F_SETLKW : F_SETLK, (can_sleep) ? F_SETLKW : F_SETLK,
lock); lock);
@ -2005,7 +2011,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
*/ */
int vfs_test_lock(struct file *filp, struct file_lock *fl) int vfs_test_lock(struct file *filp, struct file_lock *fl)
{ {
if (filp->f_op->lock) if (filp->f_op->lock && is_remote_lock(filp))
return filp->f_op->lock(filp, F_GETLK, fl); return filp->f_op->lock(filp, F_GETLK, fl);
posix_test_lock(filp, fl); posix_test_lock(filp, fl);
return 0; return 0;
@ -2129,7 +2135,7 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l)
*/ */
int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf) int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
{ {
if (filp->f_op->lock) if (filp->f_op->lock && is_remote_lock(filp))
return filp->f_op->lock(filp, cmd, fl); return filp->f_op->lock(filp, cmd, fl);
else else
return posix_lock_file(filp, fl, conf); return posix_lock_file(filp, fl, conf);
@ -2191,7 +2197,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
if (file_lock == NULL) if (file_lock == NULL)
return -ENOLCK; return -ENOLCK;
inode = file_inode(filp); inode = locks_inode(filp);
/* /*
* This might block, so we do it before checking the inode. * This might block, so we do it before checking the inode.
@ -2343,7 +2349,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
if (copy_from_user(&flock, l, sizeof(flock))) if (copy_from_user(&flock, l, sizeof(flock)))
goto out; goto out;
inode = file_inode(filp); inode = locks_inode(filp);
/* Don't allow mandatory locks on files that may be memory mapped /* Don't allow mandatory locks on files that may be memory mapped
* and shared. * and shared.
@ -2426,6 +2432,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
void locks_remove_posix(struct file *filp, fl_owner_t owner) void locks_remove_posix(struct file *filp, fl_owner_t owner)
{ {
int error; int error;
struct inode *inode = locks_inode(filp);
struct file_lock lock; struct file_lock lock;
struct file_lock_context *ctx; struct file_lock_context *ctx;
@ -2434,7 +2441,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
* posix_lock_file(). Another process could be setting a lock on this * posix_lock_file(). Another process could be setting a lock on this
* file at the same time, but we wouldn't remove that lock anyway. * file at the same time, but we wouldn't remove that lock anyway.
*/ */
ctx = smp_load_acquire(&file_inode(filp)->i_flctx); ctx = smp_load_acquire(&inode->i_flctx);
if (!ctx || list_empty(&ctx->flc_posix)) if (!ctx || list_empty(&ctx->flc_posix))
return; return;
@ -2452,7 +2459,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
if (lock.fl_ops && lock.fl_ops->fl_release_private) if (lock.fl_ops && lock.fl_ops->fl_release_private)
lock.fl_ops->fl_release_private(&lock); lock.fl_ops->fl_release_private(&lock);
trace_locks_remove_posix(file_inode(filp), &lock, error); trace_locks_remove_posix(inode, &lock, error);
} }
EXPORT_SYMBOL(locks_remove_posix); EXPORT_SYMBOL(locks_remove_posix);
@ -2469,12 +2476,12 @@ locks_remove_flock(struct file *filp, struct file_lock_context *flctx)
.fl_type = F_UNLCK, .fl_type = F_UNLCK,
.fl_end = OFFSET_MAX, .fl_end = OFFSET_MAX,
}; };
struct inode *inode = file_inode(filp); struct inode *inode = locks_inode(filp);
if (list_empty(&flctx->flc_flock)) if (list_empty(&flctx->flc_flock))
return; return;
if (filp->f_op->flock) if (filp->f_op->flock && is_remote_lock(filp))
filp->f_op->flock(filp, F_SETLKW, &fl); filp->f_op->flock(filp, F_SETLKW, &fl);
else else
flock_lock_inode(inode, &fl); flock_lock_inode(inode, &fl);
@ -2508,7 +2515,7 @@ void locks_remove_file(struct file *filp)
{ {
struct file_lock_context *ctx; struct file_lock_context *ctx;
ctx = smp_load_acquire(&file_inode(filp)->i_flctx); ctx = smp_load_acquire(&locks_inode(filp)->i_flctx);
if (!ctx) if (!ctx)
return; return;
@ -2552,7 +2559,7 @@ EXPORT_SYMBOL(posix_unblock_lock);
*/ */
int vfs_cancel_lock(struct file *filp, struct file_lock *fl) int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
{ {
if (filp->f_op->lock) if (filp->f_op->lock && is_remote_lock(filp))
return filp->f_op->lock(filp, F_CANCELLK, fl); return filp->f_op->lock(filp, F_CANCELLK, fl);
return 0; return 0;
} }
@ -2580,7 +2587,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
fl_pid = fl->fl_pid; fl_pid = fl->fl_pid;
if (fl->fl_file != NULL) if (fl->fl_file != NULL)
inode = file_inode(fl->fl_file); inode = locks_inode(fl->fl_file);
seq_printf(f, "%lld:%s ", id, pfx); seq_printf(f, "%lld:%s ", id, pfx);
if (IS_POSIX(fl)) { if (IS_POSIX(fl)) {
@ -2682,7 +2689,7 @@ static void __show_fd_locks(struct seq_file *f,
void show_fd_locks(struct seq_file *f, void show_fd_locks(struct seq_file *f,
struct file *filp, struct files_struct *files) struct file *filp, struct files_struct *files)
{ {
struct inode *inode = file_inode(filp); struct inode *inode = locks_inode(filp);
struct file_lock_context *ctx; struct file_lock_context *ctx;
int id = 0; int id = 0;

View File

@ -1015,7 +1015,7 @@ const char *get_link(struct nameidata *nd)
if (!(nd->flags & LOOKUP_RCU)) { if (!(nd->flags & LOOKUP_RCU)) {
touch_atime(&last->link); touch_atime(&last->link);
cond_resched(); cond_resched();
} else if (atime_needs_update(&last->link, inode)) { } else if (atime_needs_update_rcu(&last->link, inode)) {
if (unlikely(unlazy_walk(nd, NULL, 0))) if (unlikely(unlazy_walk(nd, NULL, 0)))
return ERR_PTR(-ECHILD); return ERR_PTR(-ECHILD);
touch_atime(&last->link); touch_atime(&last->link);

View File

@ -2700,7 +2700,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,
flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN | flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
MS_STRICTATIME); MS_STRICTATIME | MS_NOREMOTELOCK);
if (flags & MS_REMOUNT) if (flags & MS_REMOUNT)
retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags, retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,

View File

@ -68,6 +68,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
long vfs_truncate(const struct path *path, loff_t length) long vfs_truncate(const struct path *path, loff_t length)
{ {
struct inode *inode; struct inode *inode;
struct dentry *upperdentry;
long error; long error;
inode = path->dentry->d_inode; inode = path->dentry->d_inode;
@ -90,7 +91,17 @@ long vfs_truncate(const struct path *path, loff_t length)
if (IS_APPEND(inode)) if (IS_APPEND(inode))
goto mnt_drop_write_and_out; goto mnt_drop_write_and_out;
error = get_write_access(inode); /*
* If this is an overlayfs then do as if opening the file so we get
* write access on the upper inode, not on the overlay inode. For
* non-overlay filesystems d_real() is an identity function.
*/
upperdentry = d_real(path->dentry, NULL, O_WRONLY);
error = PTR_ERR(upperdentry);
if (IS_ERR(upperdentry))
goto mnt_drop_write_and_out;
error = get_write_access(upperdentry->d_inode);
if (error) if (error)
goto mnt_drop_write_and_out; goto mnt_drop_write_and_out;
@ -109,7 +120,7 @@ long vfs_truncate(const struct path *path, loff_t length)
error = do_truncate(path->dentry, length, 0, NULL); error = do_truncate(path->dentry, length, 0, NULL);
put_write_and_out: put_write_and_out:
put_write_access(inode); put_write_access(upperdentry->d_inode);
mnt_drop_write_and_out: mnt_drop_write_and_out:
mnt_drop_write(path->mnt); mnt_drop_write(path->mnt);
out: out:
@ -726,7 +737,7 @@ static int do_dentry_open(struct file *f,
if (error) if (error)
goto cleanup_all; goto cleanup_all;
error = break_lease(inode, f->f_flags); error = break_lease(locks_inode(f), f->f_flags);
if (error) if (error)
goto cleanup_all; goto cleanup_all;

View File

@ -1320,7 +1320,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
sb->s_xattr = ovl_xattr_handlers; sb->s_xattr = ovl_xattr_handlers;
sb->s_root = root_dentry; sb->s_root = root_dentry;
sb->s_fs_info = ufs; sb->s_fs_info = ufs;
sb->s_flags |= MS_POSIXACL; sb->s_flags |= MS_POSIXACL | MS_NOREMOTELOCK;
return 0; return 0;

View File

@ -598,13 +598,14 @@ posix_acl_create(struct inode *dir, umode_t *mode,
if (IS_ERR(p)) if (IS_ERR(p))
return PTR_ERR(p); return PTR_ERR(p);
ret = -ENOMEM;
clone = posix_acl_clone(p, GFP_NOFS); clone = posix_acl_clone(p, GFP_NOFS);
if (!clone) if (!clone)
goto no_mem; goto err_release;
ret = posix_acl_create_masq(clone, mode); ret = posix_acl_create_masq(clone, mode);
if (ret < 0) if (ret < 0)
goto no_mem_clone; goto err_release_clone;
if (ret == 0) if (ret == 0)
posix_acl_release(clone); posix_acl_release(clone);
@ -618,11 +619,11 @@ posix_acl_create(struct inode *dir, umode_t *mode,
return 0; return 0;
no_mem_clone: err_release_clone:
posix_acl_release(clone); posix_acl_release(clone);
no_mem: err_release:
posix_acl_release(p); posix_acl_release(p);
return -ENOMEM; return ret;
} }
EXPORT_SYMBOL_GPL(posix_acl_create); EXPORT_SYMBOL_GPL(posix_acl_create);

View File

@ -87,21 +87,7 @@ static int utimes_common(struct path *path, struct timespec *times)
*/ */
newattrs.ia_valid |= ATTR_TIMES_SET; newattrs.ia_valid |= ATTR_TIMES_SET;
} else { } else {
/* newattrs.ia_valid |= ATTR_TOUCH;
* If times is NULL (or both times are UTIME_NOW),
* then we need to check permissions, because
* inode_change_ok() won't do it.
*/
error = -EPERM;
if (IS_IMMUTABLE(inode))
goto mnt_drop_write_and_out;
error = -EACCES;
if (!inode_owner_or_capable(inode)) {
error = inode_permission(inode, MAY_WRITE);
if (error)
goto mnt_drop_write_and_out;
}
} }
retry_deleg: retry_deleg:
inode_lock(inode); inode_lock(inode);
@ -113,7 +99,6 @@ static int utimes_common(struct path *path, struct timespec *times)
goto retry_deleg; goto retry_deleg;
} }
mnt_drop_write_and_out:
mnt_drop_write(path->mnt); mnt_drop_write(path->mnt);
out: out:
return error; return error;

View File

@ -584,9 +584,10 @@ static inline struct dentry *d_real(struct dentry *dentry,
* If dentry is on an union/overlay, then return the underlying, real inode. * If dentry is on an union/overlay, then return the underlying, real inode.
* Otherwise return d_inode(). * Otherwise return d_inode().
*/ */
static inline struct inode *d_real_inode(struct dentry *dentry) static inline struct inode *d_real_inode(const struct dentry *dentry)
{ {
return d_backing_inode(d_real(dentry, NULL, 0)); /* This usage of d_real() results in const dentry */
return d_backing_inode(d_real((struct dentry *) dentry, NULL, 0));
} }

View File

@ -224,6 +224,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
#define ATTR_KILL_PRIV (1 << 14) #define ATTR_KILL_PRIV (1 << 14)
#define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */
#define ATTR_TIMES_SET (1 << 16) #define ATTR_TIMES_SET (1 << 16)
#define ATTR_TOUCH (1 << 17)
/* /*
* Whiteout is represented by a char device. The following constants define the * Whiteout is represented by a char device. The following constants define the
@ -1064,6 +1065,18 @@ struct file_lock_context {
extern void send_sigio(struct fown_struct *fown, int fd, int band); extern void send_sigio(struct fown_struct *fown, int fd, int band);
/*
* Return the inode to use for locking
*
* For overlayfs this should be the overlay inode, not the real inode returned
* by file_inode(). For any other fs file_inode(filp) and locks_inode(filp) are
* equal.
*/
static inline struct inode *locks_inode(const struct file *f)
{
return f->f_path.dentry->d_inode;
}
#ifdef CONFIG_FILE_LOCKING #ifdef CONFIG_FILE_LOCKING
extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *); extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *);
extern int fcntl_setlk(unsigned int, struct file *, unsigned int, extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
@ -1251,7 +1264,7 @@ static inline struct dentry *file_dentry(const struct file *file)
static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl) static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl)
{ {
return locks_lock_inode_wait(file_inode(filp), fl); return locks_lock_inode_wait(locks_inode(filp), fl);
} }
struct fasync_struct { struct fasync_struct {
@ -2006,7 +2019,6 @@ enum file_time_flags {
S_VERSION = 8, S_VERSION = 8,
}; };
extern bool atime_needs_update(const struct path *, struct inode *);
extern void touch_atime(const struct path *); extern void touch_atime(const struct path *);
static inline void file_accessed(struct file *file) static inline void file_accessed(struct file *file)
{ {
@ -2155,7 +2167,7 @@ static inline int mandatory_lock(struct inode *ino)
static inline int locks_verify_locked(struct file *file) static inline int locks_verify_locked(struct file *file)
{ {
if (mandatory_lock(file_inode(file))) if (mandatory_lock(locks_inode(file)))
return locks_mandatory_locked(file); return locks_mandatory_locked(file);
return 0; return 0;
} }

View File

@ -29,7 +29,11 @@ static inline int fsnotify_parent(struct path *path, struct dentry *dentry, __u3
static inline int fsnotify_perm(struct file *file, int mask) static inline int fsnotify_perm(struct file *file, int mask)
{ {
struct path *path = &file->f_path; struct path *path = &file->f_path;
struct inode *inode = file_inode(file); /*
* Do not use file_inode() here or anywhere in this file to get the
* inode. That would break *notity on overlayfs.
*/
struct inode *inode = path->dentry->d_inode;
__u32 fsnotify_mask = 0; __u32 fsnotify_mask = 0;
int ret; int ret;
@ -173,7 +177,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
static inline void fsnotify_access(struct file *file) static inline void fsnotify_access(struct file *file)
{ {
struct path *path = &file->f_path; struct path *path = &file->f_path;
struct inode *inode = file_inode(file); struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_ACCESS; __u32 mask = FS_ACCESS;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
@ -191,7 +195,7 @@ static inline void fsnotify_access(struct file *file)
static inline void fsnotify_modify(struct file *file) static inline void fsnotify_modify(struct file *file)
{ {
struct path *path = &file->f_path; struct path *path = &file->f_path;
struct inode *inode = file_inode(file); struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_MODIFY; __u32 mask = FS_MODIFY;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
@ -209,7 +213,7 @@ static inline void fsnotify_modify(struct file *file)
static inline void fsnotify_open(struct file *file) static inline void fsnotify_open(struct file *file)
{ {
struct path *path = &file->f_path; struct path *path = &file->f_path;
struct inode *inode = file_inode(file); struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_OPEN; __u32 mask = FS_OPEN;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
@ -225,7 +229,7 @@ static inline void fsnotify_open(struct file *file)
static inline void fsnotify_close(struct file *file) static inline void fsnotify_close(struct file *file)
{ {
struct path *path = &file->f_path; struct path *path = &file->f_path;
struct inode *inode = file_inode(file); struct inode *inode = path->dentry->d_inode;
fmode_t mode = file->f_mode; fmode_t mode = file->f_mode;
__u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE; __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;

View File

@ -132,6 +132,7 @@ struct inodes_stat_t {
#define MS_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */ #define MS_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */
/* These sb flags are internal to the kernel */ /* These sb flags are internal to the kernel */
#define MS_NOREMOTELOCK (1<<27)
#define MS_NOSEC (1<<28) #define MS_NOSEC (1<<28)
#define MS_BORN (1<<29) #define MS_BORN (1<<29)
#define MS_ACTIVE (1<<30) #define MS_ACTIVE (1<<30)

View File

@ -190,7 +190,7 @@ int ima_appraise_measurement(enum ima_hooks func,
{ {
static const char op[] = "appraise_data"; static const char op[] = "appraise_data";
char *cause = "unknown"; char *cause = "unknown";
struct dentry *dentry = file->f_path.dentry; struct dentry *dentry = file_dentry(file);
struct inode *inode = d_backing_inode(dentry); struct inode *inode = d_backing_inode(dentry);
enum integrity_status status = INTEGRITY_UNKNOWN; enum integrity_status status = INTEGRITY_UNKNOWN;
int rc = xattr_len, hash_start = 0; int rc = xattr_len, hash_start = 0;
@ -295,7 +295,7 @@ int ima_appraise_measurement(enum ima_hooks func,
*/ */
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
{ {
struct dentry *dentry = file->f_path.dentry; struct dentry *dentry = file_dentry(file);
int rc = 0; int rc = 0;
/* do not collect and update hash for digital signatures */ /* do not collect and update hash for digital signatures */

View File

@ -228,7 +228,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
if ((action & IMA_APPRAISE_SUBMASK) || if ((action & IMA_APPRAISE_SUBMASK) ||
strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
/* read 'security.ima' */ /* read 'security.ima' */
xattr_len = ima_read_xattr(file->f_path.dentry, &xattr_value); xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
hash_algo = ima_get_hash_algo(xattr_value, xattr_len); hash_algo = ima_get_hash_algo(xattr_value, xattr_len);