Commit c75e2475 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull third set of VFS updates from Al Viro:
 "Misc stuff all over the place.  There will be one more pile in a
  couple of days"

This is an "evil merge" that also uses the new d_count helper in
fs/configfs/dir.c, missed by commit 84d08fa8 ("helper for reading
->d_count")

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  ncpfs: fix error return code in ncp_parse_options()
  locks: move file_lock_list to a set of percpu hlist_heads and convert file_lock_lock to an lglock
  seq_file: add seq_list_*_percpu helpers
  f2fs: fix readdir incorrectness
  mode_t whack-a-mole...
  lustre: kill the pointless wrapper
  helper for reading ->d_count
parents d2b4a646 4fbeb19d
...@@ -60,8 +60,6 @@ truncate_complete_page(struct address_space *mapping, struct page *page) ...@@ -60,8 +60,6 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
ll_delete_from_page_cache(page); ll_delete_from_page_cache(page);
} }
# define d_refcount(d) ((d)->d_count)
#ifdef ATTR_OPEN #ifdef ATTR_OPEN
# define ATTR_FROM_OPEN ATTR_OPEN # define ATTR_FROM_OPEN ATTR_OPEN
#else #else
......
...@@ -99,7 +99,7 @@ static inline void l_dput(struct dentry *de) ...@@ -99,7 +99,7 @@ static inline void l_dput(struct dentry *de)
if (!de || IS_ERR(de)) if (!de || IS_ERR(de))
return; return;
//shrink_dcache_parent(de); //shrink_dcache_parent(de);
LASSERT(d_refcount(de) > 0); LASSERT(d_count(de) > 0);
dput(de); dput(de);
} }
......
...@@ -53,7 +53,7 @@ struct lprocfs_vars { ...@@ -53,7 +53,7 @@ struct lprocfs_vars {
/** /**
* /proc file mode. * /proc file mode.
*/ */
mode_t proc_mode; umode_t proc_mode;
}; };
struct lprocfs_static_vars { struct lprocfs_static_vars {
...@@ -600,11 +600,11 @@ extern int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list); ...@@ -600,11 +600,11 @@ extern int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list);
extern int lprocfs_obd_cleanup(struct obd_device *obd); extern int lprocfs_obd_cleanup(struct obd_device *obd);
extern int lprocfs_seq_create(proc_dir_entry_t *parent, const char *name, extern int lprocfs_seq_create(proc_dir_entry_t *parent, const char *name,
mode_t mode, umode_t mode,
const struct file_operations *seq_fops, const struct file_operations *seq_fops,
void *data); void *data);
extern int lprocfs_obd_seq_create(struct obd_device *dev, const char *name, extern int lprocfs_obd_seq_create(struct obd_device *dev, const char *name,
mode_t mode, umode_t mode,
const struct file_operations *seq_fops, const struct file_operations *seq_fops,
void *data); void *data);
......
...@@ -98,7 +98,7 @@ int ll_dcompare(const struct dentry *parent, const struct inode *pinode, ...@@ -98,7 +98,7 @@ int ll_dcompare(const struct dentry *parent, const struct inode *pinode,
CDEBUG(D_DENTRY, "found name %.*s(%p) flags %#x refc %d\n", CDEBUG(D_DENTRY, "found name %.*s(%p) flags %#x refc %d\n",
name->len, name->name, dentry, dentry->d_flags, name->len, name->name, dentry, dentry->d_flags,
d_refcount(dentry)); d_count(dentry));
/* mountpoint is always valid */ /* mountpoint is always valid */
if (d_mountpoint((struct dentry *)dentry)) if (d_mountpoint((struct dentry *)dentry))
...@@ -165,7 +165,7 @@ static int ll_ddelete(const struct dentry *de) ...@@ -165,7 +165,7 @@ static int ll_ddelete(const struct dentry *de)
list_empty(&de->d_subdirs) ? "" : "subdirs"); list_empty(&de->d_subdirs) ? "" : "subdirs");
/* kernel >= 2.6.38 last refcount is decreased after this function. */ /* kernel >= 2.6.38 last refcount is decreased after this function. */
LASSERT(d_refcount(de) == 1); LASSERT(d_count(de) == 1);
/* Disable this piece of code temproarily because this is called /* Disable this piece of code temproarily because this is called
* inside dcache_lock so it's not appropriate to do lots of work * inside dcache_lock so it's not appropriate to do lots of work
...@@ -190,7 +190,7 @@ static int ll_set_dd(struct dentry *de) ...@@ -190,7 +190,7 @@ static int ll_set_dd(struct dentry *de)
CDEBUG(D_DENTRY, "ldd on dentry %.*s (%p) parent %p inode %p refc %d\n", CDEBUG(D_DENTRY, "ldd on dentry %.*s (%p) parent %p inode %p refc %d\n",
de->d_name.len, de->d_name.name, de, de->d_parent, de->d_inode, de->d_name.len, de->d_name.name, de, de->d_parent, de->d_inode,
d_refcount(de)); d_count(de));
if (de->d_fsdata == NULL) { if (de->d_fsdata == NULL) {
struct ll_dentry_data *lld; struct ll_dentry_data *lld;
...@@ -540,7 +540,7 @@ int ll_revalidate_it(struct dentry *de, int lookup_flags, ...@@ -540,7 +540,7 @@ int ll_revalidate_it(struct dentry *de, int lookup_flags,
CDEBUG(D_DENTRY, "revalidated dentry %.*s (%p) parent %p " CDEBUG(D_DENTRY, "revalidated dentry %.*s (%p) parent %p "
"inode %p refc %d\n", de->d_name.len, "inode %p refc %d\n", de->d_name.len,
de->d_name.name, de, de->d_parent, de->d_inode, de->d_name.name, de, de->d_parent, de->d_inode,
d_refcount(de)); d_count(de));
ll_set_lock_data(exp, de->d_inode, it, &bits); ll_set_lock_data(exp, de->d_inode, it, &bits);
......
...@@ -1529,12 +1529,12 @@ static inline void d_lustre_invalidate(struct dentry *dentry, int nested) ...@@ -1529,12 +1529,12 @@ static inline void d_lustre_invalidate(struct dentry *dentry, int nested)
{ {
CDEBUG(D_DENTRY, "invalidate dentry %.*s (%p) parent %p inode %p " CDEBUG(D_DENTRY, "invalidate dentry %.*s (%p) parent %p inode %p "
"refc %d\n", dentry->d_name.len, dentry->d_name.name, dentry, "refc %d\n", dentry->d_name.len, dentry->d_name.name, dentry,
dentry->d_parent, dentry->d_inode, d_refcount(dentry)); dentry->d_parent, dentry->d_inode, d_count(dentry));
spin_lock_nested(&dentry->d_lock, spin_lock_nested(&dentry->d_lock,
nested ? DENTRY_D_LOCK_NESTED : DENTRY_D_LOCK_NORMAL); nested ? DENTRY_D_LOCK_NESTED : DENTRY_D_LOCK_NORMAL);
__d_lustre_invalidate(dentry); __d_lustre_invalidate(dentry);
if (d_refcount(dentry) == 0) if (d_count(dentry) == 0)
__d_drop(dentry); __d_drop(dentry);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
} }
......
...@@ -659,7 +659,7 @@ void lustre_dump_dentry(struct dentry *dentry, int recur) ...@@ -659,7 +659,7 @@ void lustre_dump_dentry(struct dentry *dentry, int recur)
" flags=0x%x, fsdata=%p, %d subdirs\n", dentry, " flags=0x%x, fsdata=%p, %d subdirs\n", dentry,
dentry->d_name.len, dentry->d_name.name, dentry->d_name.len, dentry->d_name.name,
dentry->d_parent->d_name.len, dentry->d_parent->d_name.name, dentry->d_parent->d_name.len, dentry->d_parent->d_name.name,
dentry->d_parent, dentry->d_inode, d_refcount(dentry), dentry->d_parent, dentry->d_inode, d_count(dentry),
dentry->d_flags, dentry->d_fsdata, subdirs); dentry->d_flags, dentry->d_fsdata, subdirs);
if (dentry->d_inode != NULL) if (dentry->d_inode != NULL)
ll_dump_inode(dentry->d_inode); ll_dump_inode(dentry->d_inode);
......
...@@ -409,7 +409,7 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de) ...@@ -409,7 +409,7 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
iput(inode); iput(inode);
CDEBUG(D_DENTRY, CDEBUG(D_DENTRY,
"Reuse dentry %p inode %p refc %d flags %#x\n", "Reuse dentry %p inode %p refc %d flags %#x\n",
new, new->d_inode, d_refcount(new), new->d_flags); new, new->d_inode, d_count(new), new->d_flags);
return new; return new;
} }
} }
...@@ -417,7 +417,7 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de) ...@@ -417,7 +417,7 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
__d_lustre_invalidate(de); __d_lustre_invalidate(de);
d_add(de, inode); d_add(de, inode);
CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n", CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n",
de, de->d_inode, d_refcount(de), de->d_flags); de, de->d_inode, d_count(de), de->d_flags);
return de; return de;
} }
......
...@@ -121,8 +121,8 @@ void push_ctxt(struct lvfs_run_ctxt *save, struct lvfs_run_ctxt *new_ctx, ...@@ -121,8 +121,8 @@ void push_ctxt(struct lvfs_run_ctxt *save, struct lvfs_run_ctxt *new_ctx,
OBD_SET_CTXT_MAGIC(save); OBD_SET_CTXT_MAGIC(save);
save->fs = get_fs(); save->fs = get_fs();
LASSERT(d_refcount(cfs_fs_pwd(current->fs))); LASSERT(d_count(cfs_fs_pwd(current->fs)));
LASSERT(d_refcount(new_ctx->pwd)); LASSERT(d_count(new_ctx->pwd));
save->pwd = dget(cfs_fs_pwd(current->fs)); save->pwd = dget(cfs_fs_pwd(current->fs));
save->pwdmnt = mntget(cfs_fs_mnt(current->fs)); save->pwdmnt = mntget(cfs_fs_mnt(current->fs));
save->luc.luc_umask = current_umask(); save->luc.luc_umask = current_umask();
......
...@@ -73,7 +73,7 @@ proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root, ...@@ -73,7 +73,7 @@ proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
struct file_operations *fops) struct file_operations *fops)
{ {
proc_dir_entry_t *proc; proc_dir_entry_t *proc;
mode_t mode = 0; umode_t mode = 0;
if (root == NULL || name == NULL || fops == NULL) if (root == NULL || name == NULL || fops == NULL)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -140,7 +140,7 @@ int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list, ...@@ -140,7 +140,7 @@ int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
while (list->name != NULL) { while (list->name != NULL) {
struct proc_dir_entry *proc; struct proc_dir_entry *proc;
mode_t mode = 0; umode_t mode = 0;
if (list->proc_mode != 0000) { if (list->proc_mode != 0000) {
mode = list->proc_mode; mode = list->proc_mode;
...@@ -1899,7 +1899,7 @@ EXPORT_SYMBOL(lprocfs_find_named_value); ...@@ -1899,7 +1899,7 @@ EXPORT_SYMBOL(lprocfs_find_named_value);
int lprocfs_seq_create(proc_dir_entry_t *parent, int lprocfs_seq_create(proc_dir_entry_t *parent,
const char *name, const char *name,
mode_t mode, umode_t mode,
const struct file_operations *seq_fops, const struct file_operations *seq_fops,
void *data) void *data)
{ {
...@@ -1919,7 +1919,7 @@ EXPORT_SYMBOL(lprocfs_seq_create); ...@@ -1919,7 +1919,7 @@ EXPORT_SYMBOL(lprocfs_seq_create);
int lprocfs_obd_seq_create(struct obd_device *dev, int lprocfs_obd_seq_create(struct obd_device *dev,
const char *name, const char *name,
mode_t mode, umode_t mode,
const struct file_operations *seq_fops, const struct file_operations *seq_fops,
void *data) void *data)
{ {
......
...@@ -109,7 +109,7 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev, ...@@ -109,7 +109,7 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev,
spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED); spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
/* Already gone or negative dentry (under construction) - try next */ /* Already gone or negative dentry (under construction) - try next */
if (q->d_count == 0 || !simple_positive(q)) { if (!d_count(q) || !simple_positive(q)) {
spin_unlock(&q->d_lock); spin_unlock(&q->d_lock);
next = q->d_u.d_child.next; next = q->d_u.d_child.next;
goto cont; goto cont;
...@@ -267,7 +267,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt, ...@@ -267,7 +267,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
else else
ino_count++; ino_count++;
if (p->d_count > ino_count) { if (d_count(p) > ino_count) {
top_ino->last_used = jiffies; top_ino->last_used = jiffies;
dput(p); dput(p);
return 1; return 1;
...@@ -409,7 +409,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, ...@@ -409,7 +409,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
if (!exp_leaves) { if (!exp_leaves) {
/* Path walk currently on this dentry? */ /* Path walk currently on this dentry? */
ino_count = atomic_read(&ino->count) + 1; ino_count = atomic_read(&ino->count) + 1;
if (dentry->d_count > ino_count) if (d_count(dentry) > ino_count)
goto next; goto next;
if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) {
...@@ -423,7 +423,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, ...@@ -423,7 +423,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
} else { } else {
/* Path walk currently on this dentry? */ /* Path walk currently on this dentry? */
ino_count = atomic_read(&ino->count) + 1; ino_count = atomic_read(&ino->count) + 1;
if (dentry->d_count > ino_count) if (d_count(dentry) > ino_count)
goto next; goto next;
expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
......
...@@ -179,7 +179,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) ...@@ -179,7 +179,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
spin_lock(&active->d_lock); spin_lock(&active->d_lock);
/* Already gone? */ /* Already gone? */
if (active->d_count == 0) if (!d_count(active))
goto next; goto next;
qstr = &active->d_name; qstr = &active->d_name;
......
...@@ -903,8 +903,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, ...@@ -903,8 +903,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
} else if (realdn) { } else if (realdn) {
dout("dn %p (%d) spliced with %p (%d) " dout("dn %p (%d) spliced with %p (%d) "
"inode %p ino %llx.%llx\n", "inode %p ino %llx.%llx\n",
dn, dn->d_count, dn, d_count(dn),
realdn, realdn->d_count, realdn, d_count(realdn),
realdn->d_inode, ceph_vinop(realdn->d_inode)); realdn->d_inode, ceph_vinop(realdn->d_inode));
dput(dn); dput(dn);
dn = realdn; dn = realdn;
......
...@@ -1553,7 +1553,7 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base, ...@@ -1553,7 +1553,7 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
*base = ceph_ino(temp->d_inode); *base = ceph_ino(temp->d_inode);
*plen = len; *plen = len;
dout("build_path on %p %d built %llx '%.*s'\n", dout("build_path on %p %d built %llx '%.*s'\n",
dentry, dentry->d_count, *base, len, path); dentry, d_count(dentry), *base, len, path);
return path; return path;
} }
......
...@@ -526,7 +526,7 @@ static int coda_dentry_revalidate(struct dentry *de, unsigned int flags) ...@@ -526,7 +526,7 @@ static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
if (cii->c_flags & C_FLUSH) if (cii->c_flags & C_FLUSH)
coda_flag_inode_children(inode, C_FLUSH); coda_flag_inode_children(inode, C_FLUSH);
if (de->d_count > 1) if (d_count(de) > 1)
/* pretend it's valid, but don't change the flags */ /* pretend it's valid, but don't change the flags */
goto out; goto out;
......
...@@ -387,7 +387,7 @@ static void remove_dir(struct dentry * d) ...@@ -387,7 +387,7 @@ static void remove_dir(struct dentry * d)
if (d->d_inode) if (d->d_inode)
simple_rmdir(parent->d_inode,d); simple_rmdir(parent->d_inode,d);
pr_debug(" o %s removing done (%d)\n",d->d_name.name, d->d_count); pr_debug(" o %s removing done (%d)\n",d->d_name.name, d_count(d));
dput(parent); dput(parent);
} }
......
...@@ -358,7 +358,7 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry, ...@@ -358,7 +358,7 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry,
lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent)); lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));
fsstack_copy_attr_atime(dir_inode, lower_dentry->d_parent->d_inode); fsstack_copy_attr_atime(dir_inode, lower_dentry->d_parent->d_inode);
BUG_ON(!lower_dentry->d_count); BUG_ON(!d_count(lower_dentry));
ecryptfs_set_dentry_private(dentry, dentry_info); ecryptfs_set_dentry_private(dentry, dentry_info);
ecryptfs_set_dentry_lower(dentry, lower_dentry); ecryptfs_set_dentry_lower(dentry, lower_dentry);
......
...@@ -610,13 +610,12 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -610,13 +610,12 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
unsigned long npages = dir_blocks(inode); unsigned long npages = dir_blocks(inode);
unsigned int bit_pos = 0, start_bit_pos = 0; unsigned int bit_pos = 0;
struct f2fs_dentry_block *dentry_blk = NULL; struct f2fs_dentry_block *dentry_blk = NULL;
struct f2fs_dir_entry *de = NULL; struct f2fs_dir_entry *de = NULL;
struct page *dentry_page = NULL; struct page *dentry_page = NULL;
unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK); unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);
unsigned char d_type = DT_UNKNOWN; unsigned char d_type = DT_UNKNOWN;
int slots;
bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK); bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK);
...@@ -625,7 +624,6 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -625,7 +624,6 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
if (IS_ERR(dentry_page)) if (IS_ERR(dentry_page))
continue; continue;
start_bit_pos = bit_pos;
dentry_blk = kmap(dentry_page); dentry_blk = kmap(dentry_page);
while (bit_pos < NR_DENTRY_IN_BLOCK) { while (bit_pos < NR_DENTRY_IN_BLOCK) {
bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
...@@ -634,7 +632,6 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -634,7 +632,6 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
if (bit_pos >= NR_DENTRY_IN_BLOCK) if (bit_pos >= NR_DENTRY_IN_BLOCK)
break; break;
ctx->pos += bit_pos - start_bit_pos;
de = &dentry_blk->dentry[bit_pos]; de = &dentry_blk->dentry[bit_pos];
if (de->file_type < F2FS_FT_MAX) if (de->file_type < F2FS_FT_MAX)
d_type = f2fs_filetype_table[de->file_type]; d_type = f2fs_filetype_table[de->file_type];
...@@ -644,9 +641,10 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -644,9 +641,10 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
dentry_blk->filename[bit_pos], dentry_blk->filename[bit_pos],
le16_to_cpu(de->name_len), le16_to_cpu(de->name_len),
le32_to_cpu(de->ino), d_type)) le32_to_cpu(de->ino), d_type))
goto success; goto stop;
slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
bit_pos += slots; bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
ctx->pos = n * NR_DENTRY_IN_BLOCK + bit_pos;
} }
bit_pos = 0; bit_pos = 0;
ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK; ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
...@@ -654,7 +652,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -654,7 +652,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
f2fs_put_page(dentry_page, 1); f2fs_put_page(dentry_page, 1);
dentry_page = NULL; dentry_page = NULL;
} }
success: stop:
if (dentry_page && !IS_ERR(dentry_page)) { if (dentry_page && !IS_ERR(dentry_page)) {
kunmap(dentry_page); kunmap(dentry_page);
f2fs_put_page(dentry_page, 1); f2fs_put_page(dentry_page, 1);
......
...@@ -127,6 +127,8 @@ ...@@ -127,6 +127,8 @@
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/pid_namespace.h> #include <linux/pid_namespace.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/percpu.h>
#include <linux/lglock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -155,11 +157,13 @@ int lease_break_time = 45; ...@@ -155,11 +157,13 @@ int lease_break_time = 45;
for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next)
/* /*
* The global file_lock_list is only used for displaying /proc/locks. Protected * The global file_lock_list is only used for displaying /proc/locks, so we
* by the file_lock_lock. * keep a list on each CPU, with each list protected by its own spinlock via
* the file_lock_lglock. Note that alterations to the list also require that
* the relevant i_lock is held.
*/ */
static HLIST_HEAD(file_lock_list); DEFINE_STATIC_LGLOCK(file_lock_lglock);
static DEFINE_SPINLOCK(file_lock_lock); static DEFINE_PER_CPU(struct hlist_head, file_lock_list);
/* /*
* The blocked_hash is used to find POSIX lock loops for deadlock detection. * The blocked_hash is used to find POSIX lock loops for deadlock detection.
...@@ -506,20 +510,30 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) ...@@ -506,20 +510,30 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
return fl1->fl_owner == fl2->fl_owner; return fl1->fl_owner == fl2->fl_owner;
} }
/* Must be called with the i_lock held! */
static inline void static inline void
locks_insert_global_locks(struct file_lock *fl) locks_insert_global_locks(struct file_lock *fl)
{ {
spin_lock(&file_lock_lock); lg_local_lock(&file_lock_lglock);
hlist_add_head(&fl->fl_link, &file_lock_list); fl->fl_link_cpu = smp_processor_id();
spin_unlock(&file_lock_lock); hlist_add_head(&fl->fl_link, this_cpu_ptr(&file_lock_list));
lg_local_unlock(&file_lock_lglock);
} }
/* Must be called with the i_lock held! */
static inline void static inline void
locks_delete_global_locks(struct file_lock *fl) locks_delete_global_locks(struct file_lock *fl)
{ {
spin_lock(&file_lock_lock); /*
* Avoid taking lock if already unhashed. This is safe since this check
* is done while holding the i_lock, and new insertions into the list
* also require that it be held.
*/
if (hlist_unhashed(&fl->fl_link))
return;
lg_local_lock_cpu(&file_lock_lglock, fl->fl_link_cpu);
hlist_del_init(&fl->fl_link); hlist_del_init(&fl->fl_link);
spin_unlock(&file_lock_lock); lg_local_unlock_cpu(&file_lock_lglock, fl->fl_link_cpu);
} }
static unsigned long static unsigned long
...@@ -1454,7 +1468,7 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp ...@@ -1454,7 +1468,7 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
goto out; goto out;
if ((arg == F_WRLCK) if ((arg == F_WRLCK)
&& ((dentry->d_count > 1) && ((d_count(dentry) > 1)
|| (atomic_read(&inode->i_count) > 1))) || (atomic_read(&inode->i_count) > 1)))
goto out; goto out;
...@@ -2243,6 +2257,11 @@ EXPORT_SYMBOL_GPL(vfs_cancel_lock); ...@@ -2243,6 +2257,11 @@ EXPORT_SYMBOL_GPL(vfs_cancel_lock);
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
struct locks_iterator {
int li_cpu;
loff_t li_pos;
};
static void lock_get_status(struct seq_file *f, struct file_lock *fl, static void lock_get_status(struct seq_file *f, struct file_lock *fl,
loff_t id, char *pfx) loff_t id, char *pfx)
{ {
...@@ -2316,39 +2335,41 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, ...@@ -2316,39 +2335,41 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
static int locks_show(struct seq_file *f, void *v) static int locks_show(struct seq_file *f, void *v)
{ {
struct locks_iterator *iter = f->private;
struct file_lock *fl, *bfl; struct file_lock *fl, *bfl;
fl = hlist_entry(v, struct file_lock, fl_link); fl = hlist_entry(v, struct file_lock, fl_link);
lock_get_status(f, fl, *((loff_t *)f->private), ""); lock_get_status(f, fl, iter->li_pos, "");
list_for_each_entry(bfl, &fl->fl_block, fl_block) list_for_each_entry(bfl, &fl->fl_block, fl_block)
lock_get_status(f, bfl, *((loff_t *)f->private), " ->"); lock_get_status(f, bfl, iter->li_pos, " ->");
return 0; return 0;
} }
static void *locks_start(struct seq_file *f, loff_t *pos) static void *locks_start(struct seq_file *f, loff_t *pos)
{ {
loff_t *p = f->private; struct locks_iterator *iter = f->private;
spin_lock(&file_lock_lock); iter->li_pos = *pos + 1;
lg_global_lock(&file_lock_lglock);
spin_lock(&blocked_lock_lock); spin_lock(&blocked_lock_lock);
*p = (*pos + 1); return seq_hlist_start_percpu(&file_lock_list, &iter->li_cpu, *pos);
return seq_hlist_start(&file_lock_list, *pos);
} }
static void *locks_next(struct seq_file *f, void *v, loff_t *pos) static void *locks_next(struct seq_file *f, void *v, loff_t *pos)
{ {
loff_t *p = f->private; struct locks_iterator *iter = f->private;
++*p;
return seq_hlist_next(v, &file_lock_list, pos); ++iter->li_pos;
return seq_hlist_next_percpu(v, &file_lock_list, &iter->li_cpu, pos);
} }
static void locks_stop(struct seq_file *f, void *v) static void locks_stop(struct seq_file *f, void *v)
{ {
spin_unlock(&blocked_lock_lock); spin_unlock(&blocked_lock_lock);
spin_unlock(&file_lock_lock); lg_global_unlock(&file_lock_lglock);
} }
static const struct seq_operations locks_seq_operations = { static const struct seq_operations locks_seq_operations = {
...@@ -2360,7 +2381,8 @@ static const struct seq_operations locks_seq_operations = { ...@@ -2360,7 +2381,8 @@ static const struct seq_operations locks_seq_operations = {
static int locks_open(struct inode *inode, struct file *filp) static int locks_open(struct inode *inode, struct file *filp)
{ {
return seq_open_private(filp, &locks_seq_operations, sizeof(loff_t)); return seq_open_private(filp, &locks_seq_operations,
sizeof(struct locks_iterator));
} }
static const struct file_operations proc_locks_operations = { static const struct file_operations proc_locks_operations = {
...@@ -2460,9 +2482,16 @@ EXPORT_SYMBOL(lock_may_write); ...@@ -2460,9 +2482,16 @@ EXPORT_SYMBOL(lock_may_write);
static int __init filelock_init(void) static int __init filelock_init(void)
{ {
int i;
filelock_cache = kmem_cache_create("file_lock_cache", filelock_cache = kmem_cache_create("file_lock_cache",
sizeof(struct file_lock), 0, SLAB_PANIC, NULL); sizeof(struct file_lock), 0, SLAB_PANIC, NULL);
lg_lock_init(&file_lock_lglock, "file_lock_lglock");
for_each_possible_cpu(i)
INIT_HLIST_HEAD(per_cpu_ptr(&file_lock_list, i));
return 0; return 0;
} }
......
...@@ -403,18 +403,24 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) ...@@ -403,18 +403,24 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options)
switch (optval) { switch (optval) {
case 'u': case 'u':
data->uid = make_kuid(current_user_ns(), optint); data->uid = make_kuid(current_user_ns(), optint);
if (!uid_valid(data->uid)) if (!uid_valid(data->uid)) {
ret = -EINVAL;
goto err; goto err;
}
break; break;
case 'g': case 'g':
data->gid = make_kgid(current_user_ns(), optint); data->gid = make_kgid(current_user_ns(), optint);
if (!gid_valid(data->gid)) if (!gid_valid(data->gid)) {
ret = -EINVAL;
goto err; goto err;
}
break; break;
case 'o': case 'o':
data->mounted_uid = make_kuid(current_user_ns(), optint); data->mounted_uid = make_kuid(current_user_ns(), optint);
if (!uid_valid(data->mounted_uid)) if (!uid_valid(data->mounted_uid)) {
ret = -EINVAL;
goto err; goto err;
}
break; break;
case 'm': case 'm':
data->file_mode = optint; data->file_mode = optint;
......
...@@ -1721,7 +1721,7 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1721,7 +1721,7 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)
dir->i_ino, dentry->d_name.name); dir->i_ino, dentry->d_name.name);
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
if (dentry->d_count > 1) { if (d_count(dentry) > 1) {
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
/* Start asynchronous writeout of the inode */ /* Start asynchronous writeout of the inode */
write_inode_now(dentry->d_inode, 0); write_inode_now(dentry->d_inode, 0);
...@@ -1866,7 +1866,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1866,7 +1866,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n",
old_dentry->d_parent->d_name.name, old_dentry->d_name.name, old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
new_dentry->d_parent->d_name.name, new_dentry->d_name.name, new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
new_dentry->d_count); d_count(new_dentry));
/* /*
* For non-directories, check whether the target is busy and if so, * For non-directories, check whether the target is busy and if so,
...@@ -1884,7 +1884,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1884,7 +1884,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
rehash = new_dentry; rehash = new_dentry;
} }
if (new_dentry->d_count > 2) { if (d_count(new_dentry) > 2) {
int err; int err;
/* copy the target dentry's name */ /* copy the target dentry's name */
......
...@@ -479,7 +479,7 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) ...@@ -479,7 +479,7 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_parent->d_name.name, dentry->d_name.name,
dentry->d_count); d_count(dentry));
nfs_inc_stats(dir, NFSIOS_SILLYRENAME); nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
/* /*
......
...@@ -996,7 +996,7 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, ...@@ -996,7 +996,7 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno,
static int nilfs_tree_was_touched(struct dentry *root_dentry) static int nilfs_tree_was_touched(struct dentry *root_dentry)
{ {
return root_dentry->d_count > 1; return d_count(root_dentry) > 1;
} }
/** /**
......
...@@ -921,3 +921,57 @@ struct hlist_node *seq_hlist_next_rcu(void *v, ...@@ -921,3 +921,57 @@ struct hlist_node *seq_hlist_next_rcu(void *v,
return rcu_dereference(node->next); return rcu_dereference(node->next);
} }
EXPORT_SYMBOL(seq_hlist_next_rcu); EXPORT_SYMBOL(seq_hlist_next_rcu);
/**
* seq_hlist_start_precpu - start an iteration of a percpu hlist array
* @head: pointer to percpu array of struct hlist_heads
* @cpu: pointer to cpu "cursor"
* @pos: start position of sequence
*
* Called at seq_file->op->start().
*/
struct hlist_node *
seq_hlist_start_percpu(struct hlist_head __percpu *head, int *cpu, loff_t pos)
{
struct hlist_node *node;
for_each_possible_cpu(*cpu) {
hlist_for_each(node, per_cpu_ptr(head, *cpu)) {
if (pos-- == 0)
return node;
}
}
return NULL;
}
EXPORT_SYMBOL(seq_hlist_start_percpu);
/**
* seq_hlist_next_percpu - move to the next position of the percpu hlist array
* @v: pointer to current hlist_node
* @head: pointer to percpu array of struct hlist_heads
* @cpu: pointer to cpu "cursor"
* @pos: start position of sequence
*
* Called at seq_file->op->next().
*/
struct hlist_node *
seq_hlist_next_percpu(void *v, struct hlist_head __percpu *head,
int *cpu, loff_t *pos)
{
struct hlist_node *node = v;
++*pos;
if (node->next)
return node->next;
for (*cpu = cpumask_next(*cpu, cpu_possible_mask); *cpu < nr_cpu_ids;
*cpu = cpumask_next(*cpu, cpu_possible_mask)) {
struct hlist_head *bucket = per_cpu_ptr(head, *cpu);
if (!hlist_empty(bucket))
return bucket->first;
}
return NULL;
}
EXPORT_SYMBOL(seq_hlist_next_percpu);
...@@ -324,6 +324,11 @@ static inline int __d_rcu_to_refcount(struct dentry *dentry, unsigned seq) ...@@ -324,6 +324,11 @@ static inline int __d_rcu_to_refcount(struct dentry *dentry, unsigned seq)
return ret; return ret;
} }
static inline unsigned d_count(struct dentry *dentry)
{
return dentry->d_count;
}
/* validate "insecure" dentry pointer */ /* validate "insecure" dentry pointer */
extern int d_validate(struct dentry *, struct dentry *); extern int d_validate(struct dentry *, struct dentry *);
......
...@@ -954,6 +954,7 @@ struct file_lock { ...@@ -954,6 +954,7 @@ struct file_lock {
unsigned int fl_flags; unsigned int fl_flags;
unsigned char fl_type; unsigned char fl_type;
unsigned int fl_pid; unsigned int fl_pid;
int fl_link_cpu; /* what cpu's list is this on? */
struct pid *fl_nspid; struct pid *fl_nspid;
wait_queue_head_t fl_wait; wait_queue_head_t fl_wait;
struct file *fl_file; struct file *fl_file;
......
...@@ -173,4 +173,10 @@ extern struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head, ...@@ -173,4 +173,10 @@ extern struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head,
extern struct hlist_node *seq_hlist_next_rcu(void *v, extern struct hlist_node *seq_hlist_next_rcu(void *v,
struct hlist_head *head, struct hlist_head *head,
loff_t *ppos); loff_t *ppos);
/* Helpers for iterating over per-cpu hlist_head-s in seq_files */
extern struct hlist_node *seq_hlist_start_percpu(struct hlist_head __percpu *head, int *cpu, loff_t pos);
extern struct hlist_node *seq_hlist_next_percpu(void *v, struct hlist_head __percpu *head, int *cpu, loff_t *pos);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment