aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/fs/ncpfs
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2013-07-12 12:34:42 +0200
committerThomas Gleixner <tglx@linutronix.de>2013-07-12 12:34:42 +0200
commitf2006e27396f55276f24434f56e208d86e7f9908 (patch)
tree71896db916d33888b4286f80117d3cac0da40e6d /fs/ncpfs
parentMerge branch 'timers/core' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/linux-dynticks into timers/urgent (diff)
parentMerge tag 'dm-3.11-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-dm (diff)
downloadwireguard-linux-f2006e27396f55276f24434f56e208d86e7f9908.tar.xz
wireguard-linux-f2006e27396f55276f24434f56e208d86e7f9908.zip
Merge branch 'linus' into timers/urgent
Get upstream changes so we can apply fixes against them Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to '')
-rw-r--r--fs/ncpfs/dir.c45
-rw-r--r--fs/ncpfs/inode.c16
-rw-r--r--fs/ncpfs/mmap.c2
3 files changed, 38 insertions, 25 deletions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 0e7f00298213..3be047474bfc 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -73,10 +73,8 @@ const struct inode_operations ncp_dir_inode_operations =
* Dentry operations routines
*/
static int ncp_lookup_validate(struct dentry *, unsigned int);
-static int ncp_hash_dentry(const struct dentry *, const struct inode *,
- struct qstr *);
-static int ncp_compare_dentry(const struct dentry *, const struct inode *,
- const struct dentry *, const struct inode *,
+static int ncp_hash_dentry(const struct dentry *, struct qstr *);
+static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
unsigned int, const char *, const struct qstr *);
static int ncp_delete_dentry(const struct dentry *);
@@ -119,11 +117,19 @@ static inline int ncp_case_sensitive(const struct inode *i)
/*
* Note: leave the hash unchanged if the directory
* is case-sensitive.
+ *
+ * Accessing the parent inode can be racy under RCU pathwalking.
+ * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
+ * the callers will handle races.
*/
static int
-ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
- struct qstr *this)
+ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
{
+ struct inode *inode = ACCESS_ONCE(dentry->d_inode);
+
+ if (!inode)
+ return 0;
+
if (!ncp_case_sensitive(inode)) {
struct super_block *sb = dentry->d_sb;
struct nls_table *t;
@@ -140,14 +146,24 @@ ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
return 0;
}
+/*
+ * Accessing the parent inode can be racy under RCU pathwalking.
+ * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
+ * the callers will handle races.
+ */
static int
-ncp_compare_dentry(const struct dentry *parent, const struct inode *pinode,
- const struct dentry *dentry, const struct inode *inode,
+ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
+ struct inode *pinode;
+
if (len != name->len)
return 1;
+ pinode = ACCESS_ONCE(parent->d_inode);
+ if (!pinode)
+ return 1;
+
if (ncp_case_sensitive(pinode))
return strncmp(str, name->name, len);
@@ -660,8 +676,6 @@ end_advance:
ctl.valid = 0;
if (!ctl.filled && (ctl.fpos == ctx->pos)) {
if (!ino)
- ino = find_inode_number(dentry, &qname);
- if (!ino)
ino = iunique(dir->i_sb, 2);
ctl.filled = !dir_emit(ctx, qname.name, qname.len,
ino, DT_UNKNOWN);
@@ -1123,17 +1137,6 @@ 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)) {
- /*
- * 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);
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 26910c8154da..4659da67e7f6 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -403,18 +403,24 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options)
switch (optval) {
case 'u':
data->uid = make_kuid(current_user_ns(), optint);
- if (!uid_valid(data->uid))
+ if (!uid_valid(data->uid)) {
+ ret = -EINVAL;
goto err;
+ }
break;
case 'g':
data->gid = make_kgid(current_user_ns(), optint);
- if (!gid_valid(data->gid))
+ if (!gid_valid(data->gid)) {
+ ret = -EINVAL;
goto err;
+ }
break;
case 'o':
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;
+ }
break;
case 'm':
data->file_mode = optint;
@@ -891,6 +897,10 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
if (!server) /* How this could happen? */
goto out;
+ result = -EPERM;
+ if (IS_DEADDIR(dentry->d_inode))
+ goto out;
+
/* ageing the dentry to force validation */
ncp_age_dentry(server, dentry);
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index ee24df5af1f9..3c5dd55d284c 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -117,7 +117,7 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma)
return -EINVAL;
/* we do not support files bigger than 4GB... We eventually
supports just 4GB... */
- if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff
+ if (vma_pages(vma) + vma->vm_pgoff
> (1U << (32 - PAGE_SHIFT)))
return -EFBIG;