From: Al Viro Date: Sat, 8 Oct 2016 15:00:01 +0000 (-0400) Subject: Merge remote-tracking branch 'ovl/misc' into work.misc X-Git-Tag: v4.9-rc1~57^2~1 X-Git-Url: http://git.cascardo.info/?p=cascardo%2Flinux.git;a=commitdiff_plain;h=f334bcd94b7d3c0fbc34d518a86548f451ab5faf;hp=-c Merge remote-tracking branch 'ovl/misc' into work.misc --- f334bcd94b7d3c0fbc34d518a86548f451ab5faf diff --combined fs/inode.c index 691c00747e72,4a1fc1631e00..a3c7ba7f6b59 --- a/fs/inode.c +++ b/fs/inode.c @@@ -1021,17 -1021,13 +1021,17 @@@ struct inode *iget5_locked(struct super { struct hlist_head *head = inode_hashtable + hash(sb, hashval); struct inode *inode; - +again: spin_lock(&inode_hash_lock); inode = find_inode(sb, head, test, data); spin_unlock(&inode_hash_lock); if (inode) { wait_on_inode(inode); + if (unlikely(inode_unhashed(inode))) { + iput(inode); + goto again; + } return inode; } @@@ -1068,10 -1064,6 +1068,10 @@@ destroy_inode(inode); inode = old; wait_on_inode(inode); + if (unlikely(inode_unhashed(inode))) { + iput(inode); + goto again; + } } return inode; @@@ -1099,16 -1091,12 +1099,16 @@@ struct inode *iget_locked(struct super_ { struct hlist_head *head = inode_hashtable + hash(sb, ino); struct inode *inode; - +again: spin_lock(&inode_hash_lock); inode = find_inode_fast(sb, head, ino); spin_unlock(&inode_hash_lock); if (inode) { wait_on_inode(inode); + if (unlikely(inode_unhashed(inode))) { + iput(inode); + goto again; + } return inode; } @@@ -1143,10 -1131,6 +1143,10 @@@ destroy_inode(inode); inode = old; wait_on_inode(inode); + if (unlikely(inode_unhashed(inode))) { + iput(inode); + goto again; + } } return inode; } @@@ -1282,16 -1266,10 +1282,16 @@@ EXPORT_SYMBOL(ilookup5_nowait) struct inode *ilookup5(struct super_block *sb, unsigned long hashval, int (*test)(struct inode *, void *), void *data) { - struct inode *inode = ilookup5_nowait(sb, hashval, test, data); - - if (inode) + struct inode *inode; +again: + inode = ilookup5_nowait(sb, hashval, test, data); + if (inode) { wait_on_inode(inode); + if (unlikely(inode_unhashed(inode))) { + iput(inode); + goto again; + } + } return inode; } EXPORT_SYMBOL(ilookup5); @@@ -1308,18 -1286,13 +1308,18 @@@ struct inode *ilookup(struct super_bloc { struct hlist_head *head = inode_hashtable + hash(sb, ino); struct inode *inode; - +again: spin_lock(&inode_hash_lock); inode = find_inode_fast(sb, head, ino); spin_unlock(&inode_hash_lock); - if (inode) + if (inode) { wait_on_inode(inode); + if (unlikely(inode_unhashed(inode))) { + iput(inode); + goto again; + } + } return inode; } EXPORT_SYMBOL(ilookup); @@@ -1562,17 -1535,37 +1562,37 @@@ sector_t bmap(struct inode *inode, sect } 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 * earlier than either the ctime or mtime or if at least a day has * passed since the last atime update. */ - static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, - struct timespec now) + static int relatime_need_update(const struct path *path, struct inode *inode, + struct timespec now, bool rcu) { - if (!(mnt->mnt_flags & MNT_RELATIME)) + if (!(path->mnt->mnt_flags & MNT_RELATIME)) return 1; + + update_ovl_inode_times(path->dentry, inode, rcu); /* * Is mtime younger than atime? If yes, update atime: */ @@@ -1639,7 -1632,8 +1659,8 @@@ static int update_time(struct inode *in * This function automatically handles read only file systems and media, * 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 timespec now; @@@ -1665,7 -1659,7 +1686,7 @@@ now = current_fs_time(inode->i_sb); - if (!relatime_need_update(mnt, inode, now)) + if (!relatime_need_update(path, inode, now, rcu)) return false; if (timespec_equal(&inode->i_atime, &now)) @@@ -1680,7 -1674,7 +1701,7 @@@ void touch_atime(const struct path *pat struct inode *inode = d_inode(path->dentry); struct timespec now; - if (!atime_needs_update(path, inode)) + if (!__atime_needs_update(path, inode, false)) return; if (!sb_start_write_trylock(inode->i_sb)) diff --combined fs/internal.h index 395887882315,a63da5e96148..18cfde9066a0 --- a/fs/internal.h +++ b/fs/internal.h @@@ -120,6 -120,15 +120,15 @@@ extern long prune_icache_sb(struct supe extern void inode_add_lru(struct inode *inode); 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 */ @@@ -156,7 -165,7 +165,7 @@@ extern void mnt_pin_kill(struct mount * /* * fs/nsfs.c */ -extern struct dentry_operations ns_dentry_operations; +extern const struct dentry_operations ns_dentry_operations; /* * fs/ioctl.c diff --combined fs/posix_acl.c index 8cdcbb1dd092,ea3eb6f3bf1e..87193924eb91 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@@ -598,13 -598,14 +598,14 @@@ posix_acl_create(struct inode *dir, umo if (IS_ERR(p)) return PTR_ERR(p); + ret = -ENOMEM; clone = posix_acl_clone(p, GFP_NOFS); if (!clone) - goto no_mem; + goto err_release; ret = posix_acl_create_masq(clone, mode); if (ret < 0) - goto no_mem_clone; + goto err_release_clone; if (ret == 0) posix_acl_release(clone); @@@ -618,11 -619,11 +619,11 @@@ return 0; - no_mem_clone: + err_release_clone: posix_acl_release(clone); - no_mem: + err_release: posix_acl_release(p); - return -ENOMEM; + return ret; } EXPORT_SYMBOL_GPL(posix_acl_create); @@@ -633,15 -634,15 +634,15 @@@ static void posix_acl_fix_xattr_userns struct user_namespace *to, struct user_namespace *from, void *value, size_t size) { - posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; - posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; + struct posix_acl_xattr_header *header = value; + struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end; int count; kuid_t uid; kgid_t gid; if (!value) return; - if (size < sizeof(posix_acl_xattr_header)) + if (size < sizeof(struct posix_acl_xattr_header)) return; if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) return; @@@ -691,15 -692,15 +692,15 @@@ struct posix_acl posix_acl_from_xattr(struct user_namespace *user_ns, const void *value, size_t size) { - posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; - posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; + const struct posix_acl_xattr_header *header = value; + const struct posix_acl_xattr_entry *entry = (const void *)(header + 1), *end; int count; struct posix_acl *acl; struct posix_acl_entry *acl_e; if (!value) return NULL; - if (size < sizeof(posix_acl_xattr_header)) + if (size < sizeof(struct posix_acl_xattr_header)) return ERR_PTR(-EINVAL); if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) return ERR_PTR(-EOPNOTSUPP); @@@ -760,8 -761,8 +761,8 @@@ in posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, void *buffer, size_t size) { - posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer; - posix_acl_xattr_entry *ext_entry; + struct posix_acl_xattr_header *ext_acl = buffer; + struct posix_acl_xattr_entry *ext_entry; int real_size, n; real_size = posix_acl_xattr_size(acl->a_count); @@@ -770,7 -771,7 +771,7 @@@ if (real_size > size) return -ERANGE; - ext_entry = ext_acl->a_entries; + ext_entry = (void *)(ext_acl + 1); ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); for (n=0; n < acl->a_count; n++, ext_entry++) { diff --combined include/linux/fs.h index 2f6f059d739c,8ee0f011547f..9347f4a2abed --- a/include/linux/fs.h +++ b/include/linux/fs.h @@@ -63,7 -63,7 +63,7 @@@ extern void __init files_maxfiles_init( extern struct files_stat_struct files_stat; extern unsigned long get_max_files(void); -extern int sysctl_nr_open; +extern unsigned int sysctl_nr_open; extern struct inodes_stat_t inodes_stat; extern int leases_enable, lease_break_time; extern int sysctl_protected_symlinks; @@@ -224,6 -224,7 +224,7 @@@ typedef int (dio_iodone_t)(struct kioc #define ATTR_KILL_PRIV (1 << 14) #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ #define ATTR_TIMES_SET (1 << 16) + #define ATTR_TOUCH (1 << 17) /* * Whiteout is represented by a char device. The following constants define the @@@ -1064,6 -1065,18 +1065,18 @@@ struct file_lock_context 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 extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *); extern int fcntl_setlk(unsigned int, struct file *, unsigned int, @@@ -1251,7 -1264,7 +1264,7 @@@ static inline struct dentry *file_dentr 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 { @@@ -2006,7 -2019,6 +2019,6 @@@ enum file_time_flags S_VERSION = 8, }; - extern bool atime_needs_update(const struct path *, struct inode *); extern void touch_atime(const struct path *); static inline void file_accessed(struct file *file) { @@@ -2155,7 -2167,7 +2167,7 @@@ static inline int mandatory_lock(struc 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 0; }