forked from Minki/linux
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (36 commits) Cache xattr security drop check for write v2 fs: block_page_mkwrite should wait for writeback to finish mm: Wait for writeback when grabbing pages to begin a write configfs: remove unnecessary dentry_unhash on rmdir, dir rename fat: remove unnecessary dentry_unhash on rmdir, dir rename hpfs: remove unnecessary dentry_unhash on rmdir, dir rename minix: remove unnecessary dentry_unhash on rmdir, dir rename fuse: remove unnecessary dentry_unhash on rmdir, dir rename coda: remove unnecessary dentry_unhash on rmdir, dir rename afs: remove unnecessary dentry_unhash on rmdir, dir rename affs: remove unnecessary dentry_unhash on rmdir, dir rename 9p: remove unnecessary dentry_unhash on rmdir, dir rename ncpfs: fix rename over directory with dangling references ncpfs: document dentry_unhash usage ecryptfs: remove unnecessary dentry_unhash on rmdir, dir rename hostfs: remove unnecessary dentry_unhash on rmdir, dir rename hfsplus: remove unnecessary dentry_unhash on rmdir, dir rename hfs: remove unnecessary dentry_unhash on rmdir, dir rename omfs: remove unnecessary dentry_unhash on rmdir, dir rneame udf: remove unnecessary dentry_unhash from rmdir, dir rename ...
This commit is contained in:
commit
36947a7682
@ -104,7 +104,7 @@ of the locking scheme for directory operations.
|
||||
prototypes:
|
||||
struct inode *(*alloc_inode)(struct super_block *sb);
|
||||
void (*destroy_inode)(struct inode *);
|
||||
void (*dirty_inode) (struct inode *);
|
||||
void (*dirty_inode) (struct inode *, int flags);
|
||||
int (*write_inode) (struct inode *, struct writeback_control *wbc);
|
||||
int (*drop_inode) (struct inode *);
|
||||
void (*evict_inode) (struct inode *);
|
||||
@ -126,7 +126,7 @@ locking rules:
|
||||
s_umount
|
||||
alloc_inode:
|
||||
destroy_inode:
|
||||
dirty_inode: (must not sleep)
|
||||
dirty_inode:
|
||||
write_inode:
|
||||
drop_inode: !!!inode->i_lock!!!
|
||||
evict_inode:
|
||||
|
@ -211,7 +211,7 @@ struct super_operations {
|
||||
struct inode *(*alloc_inode)(struct super_block *sb);
|
||||
void (*destroy_inode)(struct inode *);
|
||||
|
||||
void (*dirty_inode) (struct inode *);
|
||||
void (*dirty_inode) (struct inode *, int flags);
|
||||
int (*write_inode) (struct inode *, int);
|
||||
void (*drop_inode) (struct inode *);
|
||||
void (*delete_inode) (struct inode *);
|
||||
|
@ -814,7 +814,6 @@ int v9fs_vfs_unlink(struct inode *i, struct dentry *d)
|
||||
|
||||
int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
|
||||
{
|
||||
dentry_unhash(d);
|
||||
return v9fs_remove(i, d, 1);
|
||||
}
|
||||
|
||||
@ -840,9 +839,6 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct p9_fid *newdirfid;
|
||||
struct p9_wstat wstat;
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
P9_DPRINTK(P9_DEBUG_VFS, "\n");
|
||||
retval = 0;
|
||||
old_inode = old_dentry->d_inode;
|
||||
|
@ -320,8 +320,6 @@ affs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
dentry->d_inode->i_ino,
|
||||
(int)dentry->d_name.len, dentry->d_name.name);
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
return affs_remove_header(dentry);
|
||||
}
|
||||
|
||||
@ -419,9 +417,6 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct buffer_head *bh = NULL;
|
||||
int retval;
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
pr_debug("AFFS: rename(old=%u,\"%*s\" to new=%u,\"%*s\")\n",
|
||||
(u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
|
||||
(u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
|
||||
|
@ -845,8 +845,6 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
_enter("{%x:%u},{%s}",
|
||||
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
ret = -ENAMETOOLONG;
|
||||
if (dentry->d_name.len >= AFSNAMEMAX)
|
||||
goto error;
|
||||
@ -1148,9 +1146,6 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct key *key;
|
||||
int ret;
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
vnode = AFS_FS_I(old_dentry->d_inode);
|
||||
orig_dvnode = AFS_FS_I(old_dir);
|
||||
new_dvnode = AFS_FS_I(new_dir);
|
||||
|
@ -175,6 +175,13 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if ((ia_valid & ATTR_MODE)) {
|
||||
mode_t amode = attr->ia_mode;
|
||||
/* Flag setting protected by i_mutex */
|
||||
if (is_sxid(amode))
|
||||
inode->i_flags &= ~S_NOSEC;
|
||||
}
|
||||
|
||||
now = current_fs_time(inode->i_sb);
|
||||
|
||||
attr->ia_ctime = now;
|
||||
|
@ -224,9 +224,6 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct bfs_sb_info *info;
|
||||
int error = -ENOENT;
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
old_bh = new_bh = NULL;
|
||||
old_inode = old_dentry->d_inode;
|
||||
if (S_ISDIR(old_inode->i_mode))
|
||||
|
16
fs/bio.c
16
fs/bio.c
@ -638,10 +638,11 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
|
||||
* @offset: vec entry offset
|
||||
*
|
||||
* Attempt to add a page to the bio_vec maplist. This can fail for a
|
||||
* number of reasons, such as the bio being full or target block
|
||||
* device limitations. The target block device must allow bio's
|
||||
* smaller than PAGE_SIZE, so it is always possible to add a single
|
||||
* page to an empty bio. This should only be used by REQ_PC bios.
|
||||
* number of reasons, such as the bio being full or target block device
|
||||
* limitations. The target block device must allow bio's up to PAGE_SIZE,
|
||||
* so it is always possible to add a single page to an empty bio.
|
||||
*
|
||||
* This should only be used by REQ_PC bios.
|
||||
*/
|
||||
int bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page *page,
|
||||
unsigned int len, unsigned int offset)
|
||||
@ -659,10 +660,9 @@ EXPORT_SYMBOL(bio_add_pc_page);
|
||||
* @offset: vec entry offset
|
||||
*
|
||||
* Attempt to add a page to the bio_vec maplist. This can fail for a
|
||||
* number of reasons, such as the bio being full or target block
|
||||
* device limitations. The target block device must allow bio's
|
||||
* smaller than PAGE_SIZE, so it is always possible to add a single
|
||||
* page to an empty bio.
|
||||
* number of reasons, such as the bio being full or target block device
|
||||
* limitations. The target block device must allow bio's up to PAGE_SIZE,
|
||||
* so it is always possible to add a single page to an empty bio.
|
||||
*/
|
||||
int bio_add_page(struct bio *bio, struct page *page, unsigned int len,
|
||||
unsigned int offset)
|
||||
|
@ -2524,7 +2524,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
|
||||
int btrfs_readpage(struct file *file, struct page *page);
|
||||
void btrfs_evict_inode(struct inode *inode);
|
||||
int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc);
|
||||
void btrfs_dirty_inode(struct inode *inode);
|
||||
void btrfs_dirty_inode(struct inode *inode, int flags);
|
||||
struct inode *btrfs_alloc_inode(struct super_block *sb);
|
||||
void btrfs_destroy_inode(struct inode *inode);
|
||||
int btrfs_drop_inode(struct inode *inode);
|
||||
|
@ -4294,7 +4294,7 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
||||
* FIXME, needs more benchmarking...there are no reasons other than performance
|
||||
* to keep or drop this code.
|
||||
*/
|
||||
void btrfs_dirty_inode(struct inode *inode)
|
||||
void btrfs_dirty_inode(struct inode *inode, int flags)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_trans_handle *trans;
|
||||
|
@ -2382,6 +2382,7 @@ int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
|
||||
ret = -EAGAIN;
|
||||
goto out_unlock;
|
||||
}
|
||||
wait_on_page_writeback(page);
|
||||
return 0;
|
||||
out_unlock:
|
||||
unlock_page(page);
|
||||
|
@ -336,8 +336,6 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
|
||||
int len = de->d_name.len;
|
||||
int error;
|
||||
|
||||
dentry_unhash(de);
|
||||
|
||||
error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
|
||||
if (!error) {
|
||||
/* VFS may delete the child */
|
||||
@ -361,9 +359,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
int new_length = new_dentry->d_name.len;
|
||||
int error;
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
|
||||
coda_i2f(new_dir), old_length, new_length,
|
||||
(const char *) old_name, (const char *)new_name);
|
||||
|
@ -1359,8 +1359,6 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
struct module *subsys_owner = NULL, *dead_item_owner = NULL;
|
||||
int ret;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
if (dentry->d_parent == configfs_sb->s_root)
|
||||
return -EPERM;
|
||||
|
||||
|
@ -521,8 +521,6 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
struct dentry *lower_dir_dentry;
|
||||
int rc;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
dget(dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
@ -575,9 +573,6 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct dentry *lower_new_dir_dentry;
|
||||
struct dentry *trap = NULL;
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
|
||||
lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
|
||||
dget(lower_old_dentry);
|
||||
|
@ -3392,7 +3392,7 @@ int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode)
|
||||
* so would cause a commit on atime updates, which we don't bother doing.
|
||||
* We handle synchronous inodes at the highest possible level.
|
||||
*/
|
||||
void ext3_dirty_inode(struct inode *inode)
|
||||
void ext3_dirty_inode(struct inode *inode, int flags)
|
||||
{
|
||||
handle_t *current_handle = ext3_journal_current_handle();
|
||||
handle_t *handle;
|
||||
|
@ -1813,7 +1813,7 @@ extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
extern void ext4_evict_inode(struct inode *);
|
||||
extern void ext4_clear_inode(struct inode *);
|
||||
extern int ext4_sync_inode(handle_t *, struct inode *);
|
||||
extern void ext4_dirty_inode(struct inode *);
|
||||
extern void ext4_dirty_inode(struct inode *, int);
|
||||
extern int ext4_change_inode_journal_flag(struct inode *, int);
|
||||
extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
|
||||
extern int ext4_can_truncate(struct inode *inode);
|
||||
|
@ -5733,7 +5733,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
|
||||
* so would cause a commit on atime updates, which we don't bother doing.
|
||||
* We handle synchronous inodes at the highest possible level.
|
||||
*/
|
||||
void ext4_dirty_inode(struct inode *inode)
|
||||
void ext4_dirty_inode(struct inode *inode, int flags)
|
||||
{
|
||||
handle_t *handle;
|
||||
|
||||
|
@ -326,8 +326,6 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
struct fat_slot_info sinfo;
|
||||
int err;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
lock_super(sb);
|
||||
/*
|
||||
* Check whether the directory is not in use, then check
|
||||
@ -459,9 +457,6 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
|
||||
old_inode = old_dentry->d_inode;
|
||||
new_inode = new_dentry->d_inode;
|
||||
|
||||
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
err = fat_scan(old_dir, old_name, &old_sinfo);
|
||||
if (err) {
|
||||
err = -EIO;
|
||||
|
@ -824,8 +824,6 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
struct fat_slot_info sinfo;
|
||||
int err;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
lock_super(sb);
|
||||
|
||||
err = fat_dir_empty(inode);
|
||||
@ -933,9 +931,6 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
int err, is_dir, update_dotdot, corrupt = 0;
|
||||
struct super_block *sb = old_dir->i_sb;
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
|
||||
old_inode = old_dentry->d_inode;
|
||||
new_inode = new_dentry->d_inode;
|
||||
|
@ -1007,9 +1007,6 @@ static noinline void block_dump___mark_inode_dirty(struct inode *inode)
|
||||
* In short, make sure you hash any inodes _before_ you start marking
|
||||
* them dirty.
|
||||
*
|
||||
* This function *must* be atomic for the I_DIRTY_PAGES case -
|
||||
* set_page_dirty() is called under spinlock in several places.
|
||||
*
|
||||
* Note that for blockdevs, inode->dirtied_when represents the dirtying time of
|
||||
* the block-special inode (/dev/hda1) itself. And the ->dirtied_when field of
|
||||
* the kernel-internal blockdev inode represents the dirtying time of the
|
||||
@ -1028,7 +1025,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
|
||||
*/
|
||||
if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
|
||||
if (sb->s_op->dirty_inode)
|
||||
sb->s_op->dirty_inode(inode);
|
||||
sb->s_op->dirty_inode(inode, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -667,8 +667,6 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
|
||||
dentry_unhash(entry);
|
||||
|
||||
req->in.h.opcode = FUSE_RMDIR;
|
||||
req->in.h.nodeid = get_node_id(dir);
|
||||
req->in.numargs = 1;
|
||||
@ -694,9 +692,6 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
|
||||
struct fuse_conn *fc = get_fuse_conn(olddir);
|
||||
struct fuse_req *req = fuse_get_req(fc);
|
||||
|
||||
if (newent->d_inode && S_ISDIR(newent->d_inode->i_mode))
|
||||
dentry_unhash(newent);
|
||||
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
|
||||
|
@ -253,9 +253,6 @@ static int hfs_remove(struct inode *dir, struct dentry *dentry)
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int res;
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
dentry_unhash(dentry);
|
||||
|
||||
if (S_ISDIR(inode->i_mode) && inode->i_size != 2)
|
||||
return -ENOTEMPTY;
|
||||
res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
|
||||
@ -286,9 +283,6 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
|
||||
/* Unlink destination if it already exists */
|
||||
if (new_dentry->d_inode) {
|
||||
if (S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
res = hfs_remove(new_dir, new_dentry);
|
||||
if (res)
|
||||
return res;
|
||||
|
@ -370,8 +370,6 @@ static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int res;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
if (inode->i_size != 2)
|
||||
return -ENOTEMPTY;
|
||||
|
||||
@ -469,12 +467,10 @@ static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
|
||||
/* Unlink destination if it already exists */
|
||||
if (new_dentry->d_inode) {
|
||||
if (S_ISDIR(new_dentry->d_inode->i_mode)) {
|
||||
dentry_unhash(new_dentry);
|
||||
if (S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
res = hfsplus_rmdir(new_dir, new_dentry);
|
||||
} else {
|
||||
else
|
||||
res = hfsplus_unlink(new_dir, new_dentry);
|
||||
}
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
@ -683,8 +683,6 @@ int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
|
||||
char *file;
|
||||
int err;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
if ((file = dentry_name(dentry)) == NULL)
|
||||
return -ENOMEM;
|
||||
err = do_rmdir(file);
|
||||
@ -738,9 +736,6 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
|
||||
char *from_name, *to_name;
|
||||
int err;
|
||||
|
||||
if (to->d_inode && S_ISDIR(to->d_inode->i_mode))
|
||||
dentry_unhash(to);
|
||||
|
||||
if ((from_name = dentry_name(from)) == NULL)
|
||||
return -ENOMEM;
|
||||
if ((to_name = dentry_name(to)) == NULL) {
|
||||
|
@ -439,8 +439,6 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
int err;
|
||||
int r;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
hpfs_adjust_length(name, &len);
|
||||
hpfs_lock(dir->i_sb);
|
||||
err = -ENOENT;
|
||||
@ -535,9 +533,6 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct fnode *fnode;
|
||||
int err;
|
||||
|
||||
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
if ((err = hpfs_chk_name(new_name, &new_len))) return err;
|
||||
err = 0;
|
||||
hpfs_adjust_length(old_name, &old_len);
|
||||
|
54
fs/inode.c
54
fs/inode.c
@ -1,9 +1,7 @@
|
||||
/*
|
||||
* linux/fs/inode.c
|
||||
*
|
||||
* (C) 1997 Linus Torvalds
|
||||
* (C) 1999 Andrea Arcangeli <andrea@suse.de> (dynamic inode allocation)
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/dcache.h>
|
||||
@ -27,10 +25,11 @@
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/ima.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/buffer_head.h> /* for inode_has_buffers */
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* inode locking rules.
|
||||
* Inode locking rules:
|
||||
*
|
||||
* inode->i_lock protects:
|
||||
* inode->i_state, inode->i_hash, __iget()
|
||||
@ -60,54 +59,11 @@
|
||||
* inode_hash_lock
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is needed for the following functions:
|
||||
* - inode_has_buffers
|
||||
* - invalidate_bdev
|
||||
*
|
||||
* FIXME: remove all knowledge of the buffer layer from this file
|
||||
*/
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
/*
|
||||
* New inode.c implementation.
|
||||
*
|
||||
* This implementation has the basic premise of trying
|
||||
* to be extremely low-overhead and SMP-safe, yet be
|
||||
* simple enough to be "obviously correct".
|
||||
*
|
||||
* Famous last words.
|
||||
*/
|
||||
|
||||
/* inode dynamic allocation 1999, Andrea Arcangeli <andrea@suse.de> */
|
||||
|
||||
/* #define INODE_PARANOIA 1 */
|
||||
/* #define INODE_DEBUG 1 */
|
||||
|
||||
/*
|
||||
* Inode lookup is no longer as critical as it used to be:
|
||||
* most of the lookups are going to be through the dcache.
|
||||
*/
|
||||
#define I_HASHBITS i_hash_shift
|
||||
#define I_HASHMASK i_hash_mask
|
||||
|
||||
static unsigned int i_hash_mask __read_mostly;
|
||||
static unsigned int i_hash_shift __read_mostly;
|
||||
static struct hlist_head *inode_hashtable __read_mostly;
|
||||
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock);
|
||||
|
||||
/*
|
||||
* Each inode can be on two separate lists. One is
|
||||
* the hash list of the inode, used for lookups. The
|
||||
* other linked list is the "type" list:
|
||||
* "in_use" - valid inode, i_count > 0, i_nlink > 0
|
||||
* "dirty" - as "in_use" but also dirty
|
||||
* "unused" - valid inode, i_count = 0
|
||||
*
|
||||
* A "dirty" list is maintained for each super block,
|
||||
* allowing for low-overhead inode sync() operations.
|
||||
*/
|
||||
|
||||
static LIST_HEAD(inode_lru);
|
||||
static DEFINE_SPINLOCK(inode_lru_lock);
|
||||
|
||||
@ -424,8 +380,8 @@ static unsigned long hash(struct super_block *sb, unsigned long hashval)
|
||||
|
||||
tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) /
|
||||
L1_CACHE_BYTES;
|
||||
tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> I_HASHBITS);
|
||||
return tmp & I_HASHMASK;
|
||||
tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> i_hash_shift);
|
||||
return tmp & i_hash_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -605,8 +605,6 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
|
||||
int ret;
|
||||
uint32_t now = get_seconds();
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
for (fd = f->dents ; fd; fd = fd->next) {
|
||||
if (fd->ino)
|
||||
return -ENOTEMPTY;
|
||||
@ -782,9 +780,6 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
|
||||
uint8_t type;
|
||||
uint32_t now;
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
/* The VFS will check for us and prevent trying to rename a
|
||||
* file over a directory and vice versa, but if it's a directory,
|
||||
* the VFS can't check whether the victim is empty. The filesystem
|
||||
|
@ -357,7 +357,7 @@ error:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void jffs2_dirty_inode(struct inode *inode)
|
||||
void jffs2_dirty_inode(struct inode *inode, int flags)
|
||||
{
|
||||
struct iattr iattr;
|
||||
|
||||
|
@ -172,7 +172,7 @@ int jffs2_setattr (struct dentry *, struct iattr *);
|
||||
int jffs2_do_setattr (struct inode *, struct iattr *);
|
||||
struct inode *jffs2_iget(struct super_block *, unsigned long);
|
||||
void jffs2_evict_inode (struct inode *);
|
||||
void jffs2_dirty_inode(struct inode *inode);
|
||||
void jffs2_dirty_inode(struct inode *inode, int flags);
|
||||
struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
|
||||
struct jffs2_raw_inode *ri);
|
||||
int jffs2_statfs (struct dentry *, struct kstatfs *);
|
||||
|
@ -173,7 +173,7 @@ void jfs_evict_inode(struct inode *inode)
|
||||
dquot_drop(inode);
|
||||
}
|
||||
|
||||
void jfs_dirty_inode(struct inode *inode)
|
||||
void jfs_dirty_inode(struct inode *inode, int flags)
|
||||
{
|
||||
static int noisy = 5;
|
||||
|
||||
|
@ -28,7 +28,7 @@ extern struct inode *jfs_iget(struct super_block *, unsigned long);
|
||||
extern int jfs_commit_inode(struct inode *, int);
|
||||
extern int jfs_write_inode(struct inode *, struct writeback_control *);
|
||||
extern void jfs_evict_inode(struct inode *);
|
||||
extern void jfs_dirty_inode(struct inode *);
|
||||
extern void jfs_dirty_inode(struct inode *, int);
|
||||
extern void jfs_truncate(struct inode *);
|
||||
extern void jfs_truncate_nolock(struct inode *, loff_t);
|
||||
extern void jfs_free_zero_link(struct inode *);
|
||||
|
@ -360,8 +360,6 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
|
||||
|
||||
jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
/* Init inode for quota operations. */
|
||||
dquot_initialize(dip);
|
||||
dquot_initialize(ip);
|
||||
@ -1097,9 +1095,6 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
jfs_info("jfs_rename: %s %s", old_dentry->d_name.name,
|
||||
new_dentry->d_name.name);
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
dquot_initialize(old_dir);
|
||||
dquot_initialize(new_dir);
|
||||
|
||||
|
@ -273,8 +273,6 @@ static int logfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
if (!logfs_empty_dir(inode))
|
||||
return -ENOTEMPTY;
|
||||
|
||||
@ -624,9 +622,6 @@ static int logfs_rename_cross(struct inode *old_dir, struct dentry *old_dentry,
|
||||
loff_t pos;
|
||||
int err;
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
/* 1. locate source dd */
|
||||
err = logfs_get_dd(old_dir, old_dentry, &dd, &pos);
|
||||
if (err)
|
||||
|
@ -168,8 +168,6 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry)
|
||||
struct inode * inode = dentry->d_inode;
|
||||
int err = -ENOTEMPTY;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
if (minix_empty_dir(inode)) {
|
||||
err = minix_unlink(dir, dentry);
|
||||
if (!err) {
|
||||
@ -192,9 +190,6 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
|
||||
struct minix_dir_entry * old_de;
|
||||
int err = -ENOENT;
|
||||
|
||||
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
old_de = minix_find_entry(old_dentry, &old_page);
|
||||
if (!old_de)
|
||||
goto out;
|
||||
|
41
fs/namei.c
41
fs/namei.c
@ -919,12 +919,11 @@ static inline bool managed_dentry_might_block(struct dentry *dentry)
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip to top of mountpoint pile in rcuwalk mode. We abort the rcu-walk if we
|
||||
* meet a managed dentry and we're not walking to "..". True is returned to
|
||||
* continue, false to abort.
|
||||
* Try to skip to top of mountpoint pile in rcuwalk mode. Fail if
|
||||
* we meet a managed dentry that would need blocking.
|
||||
*/
|
||||
static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
|
||||
struct inode **inode, bool reverse_transit)
|
||||
struct inode **inode)
|
||||
{
|
||||
for (;;) {
|
||||
struct vfsmount *mounted;
|
||||
@ -933,8 +932,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
|
||||
* that wants to block transit.
|
||||
*/
|
||||
*inode = path->dentry->d_inode;
|
||||
if (!reverse_transit &&
|
||||
unlikely(managed_dentry_might_block(path->dentry)))
|
||||
if (unlikely(managed_dentry_might_block(path->dentry)))
|
||||
return false;
|
||||
|
||||
if (!d_mountpoint(path->dentry))
|
||||
@ -947,16 +945,24 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
|
||||
path->dentry = mounted->mnt_root;
|
||||
nd->seq = read_seqcount_begin(&path->dentry->d_seq);
|
||||
}
|
||||
|
||||
if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
|
||||
return reverse_transit;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void follow_mount_rcu(struct nameidata *nd)
|
||||
{
|
||||
while (d_mountpoint(nd->path.dentry)) {
|
||||
struct vfsmount *mounted;
|
||||
mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry, 1);
|
||||
if (!mounted)
|
||||
break;
|
||||
nd->path.mnt = mounted;
|
||||
nd->path.dentry = mounted->mnt_root;
|
||||
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
|
||||
}
|
||||
}
|
||||
|
||||
static int follow_dotdot_rcu(struct nameidata *nd)
|
||||
{
|
||||
struct inode *inode = nd->inode;
|
||||
|
||||
set_root_rcu(nd);
|
||||
|
||||
while (1) {
|
||||
@ -972,7 +978,6 @@ static int follow_dotdot_rcu(struct nameidata *nd)
|
||||
seq = read_seqcount_begin(&parent->d_seq);
|
||||
if (read_seqcount_retry(&old->d_seq, nd->seq))
|
||||
goto failed;
|
||||
inode = parent->d_inode;
|
||||
nd->path.dentry = parent;
|
||||
nd->seq = seq;
|
||||
break;
|
||||
@ -980,10 +985,9 @@ static int follow_dotdot_rcu(struct nameidata *nd)
|
||||
if (!follow_up_rcu(&nd->path))
|
||||
break;
|
||||
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
|
||||
inode = nd->path.dentry->d_inode;
|
||||
}
|
||||
__follow_mount_rcu(nd, &nd->path, &inode, true);
|
||||
nd->inode = inode;
|
||||
follow_mount_rcu(nd);
|
||||
nd->inode = nd->path.dentry->d_inode;
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
@ -1157,8 +1161,11 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
|
||||
}
|
||||
path->mnt = mnt;
|
||||
path->dentry = dentry;
|
||||
if (likely(__follow_mount_rcu(nd, path, inode, false)))
|
||||
return 0;
|
||||
if (unlikely(!__follow_mount_rcu(nd, path, inode)))
|
||||
goto unlazy;
|
||||
if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
|
||||
goto unlazy;
|
||||
return 0;
|
||||
unlazy:
|
||||
if (unlazy_walk(nd, dentry))
|
||||
return -ECHILD;
|
||||
|
@ -1033,8 +1033,11 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
DPRINTK("ncp_rmdir: removing %s/%s\n",
|
||||
dentry->d_parent->d_name.name, dentry->d_name.name);
|
||||
|
||||
/*
|
||||
* fail with EBUSY if there are still references to this
|
||||
* directory.
|
||||
*/
|
||||
dentry_unhash(dentry);
|
||||
|
||||
error = -EBUSY;
|
||||
if (!d_unhashed(dentry))
|
||||
goto out;
|
||||
@ -1141,8 +1144,16 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
|
||||
new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) {
|
||||
/*
|
||||
* fail with EBUSY if there are still references to this
|
||||
* directory.
|
||||
*/
|
||||
dentry_unhash(new_dentry);
|
||||
error = -EBUSY;
|
||||
if (!d_unhashed(new_dentry))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ncp_age_dentry(server, old_dentry);
|
||||
ncp_age_dentry(server, new_dentry);
|
||||
|
@ -917,7 +917,7 @@ int nilfs_mark_inode_dirty(struct inode *inode)
|
||||
* construction. This function can be called both as a single operation
|
||||
* and as a part of indivisible file operations.
|
||||
*/
|
||||
void nilfs_dirty_inode(struct inode *inode)
|
||||
void nilfs_dirty_inode(struct inode *inode, int flags)
|
||||
{
|
||||
struct nilfs_transaction_info ti;
|
||||
struct nilfs_mdt_info *mdi = NILFS_MDT(inode);
|
||||
|
@ -334,8 +334,6 @@ static int nilfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
struct nilfs_transaction_info ti;
|
||||
int err;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
err = nilfs_transaction_begin(dir->i_sb, &ti, 0);
|
||||
if (err)
|
||||
return err;
|
||||
@ -371,9 +369,6 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct nilfs_transaction_info ti;
|
||||
int err;
|
||||
|
||||
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
err = nilfs_transaction_begin(old_dir->i_sb, &ti, 1);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
@ -269,7 +269,7 @@ int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh);
|
||||
extern int nilfs_inode_dirty(struct inode *);
|
||||
int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty);
|
||||
extern int nilfs_mark_inode_dirty(struct inode *);
|
||||
extern void nilfs_dirty_inode(struct inode *);
|
||||
extern void nilfs_dirty_inode(struct inode *, int flags);
|
||||
int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
__u64 start, __u64 len);
|
||||
|
||||
|
@ -241,11 +241,9 @@ static int omfs_remove(struct inode *dir, struct dentry *dentry)
|
||||
int ret;
|
||||
|
||||
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
dentry_unhash(dentry);
|
||||
if (!omfs_dir_is_empty(inode))
|
||||
return -ENOTEMPTY;
|
||||
}
|
||||
if (S_ISDIR(inode->i_mode) &&
|
||||
!omfs_dir_is_empty(inode))
|
||||
return -ENOTEMPTY;
|
||||
|
||||
ret = omfs_delete_entry(dentry);
|
||||
if (ret)
|
||||
@ -382,9 +380,6 @@ static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
int err;
|
||||
|
||||
if (new_inode) {
|
||||
if (S_ISDIR(new_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
/* overwriting existing file/dir */
|
||||
err = omfs_remove(new_dir, new_dentry);
|
||||
if (err)
|
||||
|
@ -831,8 +831,6 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
INITIALIZE_PATH(path);
|
||||
struct reiserfs_dir_entry de;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
/* we will be doing 2 balancings and update 2 stat data, we change quotas
|
||||
* of the owner of the directory and of the owner of the parent directory.
|
||||
* The quota structure is possibly deleted only on last iput => outside
|
||||
@ -1227,9 +1225,6 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
unsigned long savelink = 1;
|
||||
struct timespec ctime;
|
||||
|
||||
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
/* three balancings: (1) old name removal, (2) new name insertion
|
||||
and (3) maybe "save" link insertion
|
||||
stat data updates: (1) old directory,
|
||||
|
@ -568,7 +568,7 @@ static void destroy_inodecache(void)
|
||||
}
|
||||
|
||||
/* we don't mark inodes dirty, we just log them */
|
||||
static void reiserfs_dirty_inode(struct inode *inode)
|
||||
static void reiserfs_dirty_inode(struct inode *inode, int flags)
|
||||
{
|
||||
struct reiserfs_transaction_handle th;
|
||||
|
||||
|
@ -98,7 +98,6 @@ static int xattr_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
|
||||
reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex,
|
||||
I_MUTEX_CHILD, dir->i_sb);
|
||||
dentry_unhash(dentry);
|
||||
error = dir->i_op->rmdir(dir, dentry);
|
||||
if (!error)
|
||||
dentry->d_inode->i_flags |= S_DEAD;
|
||||
|
@ -196,8 +196,6 @@ static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int err = -ENOTEMPTY;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
if (sysv_empty_dir(inode)) {
|
||||
err = sysv_unlink(dir, dentry);
|
||||
if (!err) {
|
||||
@ -224,9 +222,6 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
|
||||
struct sysv_dir_entry * old_de;
|
||||
int err = -ENOENT;
|
||||
|
||||
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
old_de = sysv_find_entry(old_dentry, &old_page);
|
||||
if (!old_de)
|
||||
goto out;
|
||||
|
@ -656,8 +656,6 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
struct ubifs_inode *dir_ui = ubifs_inode(dir);
|
||||
struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
/*
|
||||
* Budget request settings: deletion direntry, deletion inode and
|
||||
* changing the parent inode. If budgeting fails, go ahead anyway
|
||||
@ -978,9 +976,6 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
.dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
|
||||
struct timespec time;
|
||||
|
||||
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
/*
|
||||
* Budget request settings: deletion direntry, new direntry, removing
|
||||
* the old inode, and changing old and new parent directory inodes.
|
||||
|
@ -382,7 +382,7 @@ done:
|
||||
end_writeback(inode);
|
||||
}
|
||||
|
||||
static void ubifs_dirty_inode(struct inode *inode)
|
||||
static void ubifs_dirty_inode(struct inode *inode, int flags)
|
||||
{
|
||||
struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
|
||||
|
@ -783,8 +783,6 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
struct fileIdentDesc *fi, cfi;
|
||||
struct kernel_lb_addr tloc;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
retval = -ENOENT;
|
||||
fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
|
||||
if (!fi)
|
||||
@ -1083,9 +1081,6 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct kernel_lb_addr tloc;
|
||||
struct udf_inode_info *old_iinfo = UDF_I(old_inode);
|
||||
|
||||
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
|
||||
if (ofi) {
|
||||
if (ofibh.sbh != ofibh.ebh)
|
||||
|
@ -258,8 +258,6 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
|
||||
struct inode * inode = dentry->d_inode;
|
||||
int err= -ENOTEMPTY;
|
||||
|
||||
dentry_unhash(dentry);
|
||||
|
||||
lock_ufs(dir->i_sb);
|
||||
if (ufs_empty_dir (inode)) {
|
||||
err = ufs_unlink(dir, dentry);
|
||||
@ -284,9 +282,6 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct ufs_dir_entry *old_de;
|
||||
int err = -ENOENT;
|
||||
|
||||
if (new_inode && S_ISDIR(new_inode->i_mode))
|
||||
dentry_unhash(new_dentry);
|
||||
|
||||
old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page);
|
||||
if (!old_de)
|
||||
goto out;
|
||||
|
23
fs/xattr.c
23
fs/xattr.c
@ -46,18 +46,22 @@ xattr_permission(struct inode *inode, const char *name, int mask)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The trusted.* namespace can only be accessed by a privileged user.
|
||||
* The trusted.* namespace can only be accessed by privileged users.
|
||||
*/
|
||||
if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
|
||||
return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM);
|
||||
if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) {
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In user.* namespace, only regular files and directories can have
|
||||
/*
|
||||
* In the user.* namespace, only regular files and directories can have
|
||||
* extended attributes. For sticky directories, only the owner and
|
||||
* privileged user can write attributes.
|
||||
* privileged users can write attributes.
|
||||
*/
|
||||
if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
|
||||
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
|
||||
return -EPERM;
|
||||
return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
|
||||
if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
|
||||
(mask & MAY_WRITE) && !inode_owner_or_capable(inode))
|
||||
return -EPERM;
|
||||
@ -87,7 +91,11 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error = -EOPNOTSUPP;
|
||||
int issec = !strncmp(name, XATTR_SECURITY_PREFIX,
|
||||
XATTR_SECURITY_PREFIX_LEN);
|
||||
|
||||
if (issec)
|
||||
inode->i_flags &= ~S_NOSEC;
|
||||
if (inode->i_op->setxattr) {
|
||||
error = inode->i_op->setxattr(dentry, name, value, size, flags);
|
||||
if (!error) {
|
||||
@ -95,8 +103,7 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
|
||||
security_inode_post_setxattr(dentry, name, value,
|
||||
size, flags);
|
||||
}
|
||||
} else if (!strncmp(name, XATTR_SECURITY_PREFIX,
|
||||
XATTR_SECURITY_PREFIX_LEN)) {
|
||||
} else if (issec) {
|
||||
const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
|
||||
error = security_inode_setsecurity(inode, suffix, value,
|
||||
size, flags);
|
||||
|
@ -925,7 +925,8 @@ xfs_fs_inode_init_once(
|
||||
*/
|
||||
STATIC void
|
||||
xfs_fs_dirty_inode(
|
||||
struct inode *inode)
|
||||
struct inode *inode,
|
||||
int flags)
|
||||
{
|
||||
barrier();
|
||||
XFS_I(inode)->i_update_core = 1;
|
||||
|
@ -909,7 +909,7 @@ extern int ext3_setattr (struct dentry *, struct iattr *);
|
||||
extern void ext3_evict_inode (struct inode *);
|
||||
extern int ext3_sync_inode (handle_t *, struct inode *);
|
||||
extern void ext3_discard_reservation (struct inode *);
|
||||
extern void ext3_dirty_inode(struct inode *);
|
||||
extern void ext3_dirty_inode(struct inode *, int);
|
||||
extern int ext3_change_inode_journal_flag(struct inode *, int);
|
||||
extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *);
|
||||
extern int ext3_can_truncate(struct inode *inode);
|
||||
|
@ -237,6 +237,7 @@ struct inodes_stat_t {
|
||||
#define S_PRIVATE 512 /* Inode is fs-internal */
|
||||
#define S_IMA 1024 /* Inode has an associated IMA struct */
|
||||
#define S_AUTOMOUNT 2048 /* Automount/referral quasi-directory */
|
||||
#define S_NOSEC 4096 /* no suid or xattr security attributes */
|
||||
|
||||
/*
|
||||
* Note that nosuid etc flags are inode-specific: setting some file-system
|
||||
@ -273,6 +274,7 @@ struct inodes_stat_t {
|
||||
#define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE)
|
||||
#define IS_IMA(inode) ((inode)->i_flags & S_IMA)
|
||||
#define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT)
|
||||
#define IS_NOSEC(inode) ((inode)->i_flags & S_NOSEC)
|
||||
|
||||
/* the read-only stuff doesn't really belong here, but any other place is
|
||||
probably as bad and I don't want to create yet another include file. */
|
||||
@ -1618,7 +1620,7 @@ struct super_operations {
|
||||
struct inode *(*alloc_inode)(struct super_block *sb);
|
||||
void (*destroy_inode)(struct inode *);
|
||||
|
||||
void (*dirty_inode) (struct inode *);
|
||||
void (*dirty_inode) (struct inode *, int flags);
|
||||
int (*write_inode) (struct inode *, struct writeback_control *wbc);
|
||||
int (*drop_inode) (struct inode *);
|
||||
void (*evict_inode) (struct inode *);
|
||||
@ -2582,5 +2584,16 @@ int __init get_filesystem_list(char *buf);
|
||||
#define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \
|
||||
(flag & __FMODE_NONOTIFY)))
|
||||
|
||||
static inline int is_sxid(mode_t mode)
|
||||
{
|
||||
return (mode & S_ISUID) || ((mode & S_ISGID) && (mode & S_IXGRP));
|
||||
}
|
||||
|
||||
static inline void inode_has_no_xattr(struct inode *inode)
|
||||
{
|
||||
if (!is_sxid(inode->i_mode))
|
||||
inode->i_flags |= S_NOSEC;
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _LINUX_FS_H */
|
||||
|
18
mm/filemap.c
18
mm/filemap.c
@ -1982,16 +1982,26 @@ static int __remove_suid(struct dentry *dentry, int kill)
|
||||
int file_remove_suid(struct file *file)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
int killsuid = should_remove_suid(dentry);
|
||||
int killpriv = security_inode_need_killpriv(dentry);
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int killsuid;
|
||||
int killpriv;
|
||||
int error = 0;
|
||||
|
||||
/* Fast path for nothing security related */
|
||||
if (IS_NOSEC(inode))
|
||||
return 0;
|
||||
|
||||
killsuid = should_remove_suid(dentry);
|
||||
killpriv = security_inode_need_killpriv(dentry);
|
||||
|
||||
if (killpriv < 0)
|
||||
return killpriv;
|
||||
if (killpriv)
|
||||
error = security_inode_killpriv(dentry);
|
||||
if (!error && killsuid)
|
||||
error = __remove_suid(dentry, killsuid);
|
||||
if (!error)
|
||||
inode->i_flags |= S_NOSEC;
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -2327,7 +2337,7 @@ struct page *grab_cache_page_write_begin(struct address_space *mapping,
|
||||
repeat:
|
||||
page = find_lock_page(mapping, index);
|
||||
if (page)
|
||||
return page;
|
||||
goto found;
|
||||
|
||||
page = __page_cache_alloc(mapping_gfp_mask(mapping) & ~gfp_notmask);
|
||||
if (!page)
|
||||
@ -2340,6 +2350,8 @@ repeat:
|
||||
goto repeat;
|
||||
return NULL;
|
||||
}
|
||||
found:
|
||||
wait_on_page_writeback(page);
|
||||
return page;
|
||||
}
|
||||
EXPORT_SYMBOL(grab_cache_page_write_begin);
|
||||
|
Loading…
Reference in New Issue
Block a user