diff options
Diffstat (limited to 'fs')
79 files changed, 1493 insertions, 767 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index e31f3691b151..cc28a69246a7 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -220,7 +220,7 @@ config JBD config JBD_DEBUG bool "JBD (ext3) debugging support" - depends on JBD + depends on JBD && DEBUG_FS help If you are using the ext3 journaled file system (or potentially any other file system/device using JBD), this option allows you to @@ -229,10 +229,10 @@ config JBD_DEBUG debugging output will be turned off. If you select Y here, then you will be able to turn on debugging - with "echo N > /proc/sys/fs/jbd-debug", where N is a number between - 1 and 5, the higher the number, the more debugging output is - generated. To turn debugging off again, do - "echo 0 > /proc/sys/fs/jbd-debug". + with "echo N > /sys/kernel/debug/jbd/jbd-debug", where N is a + number between 1 and 5, the higher the number, the more debugging + output is generated. To turn debugging off again, do + "echo 0 > /sys/kernel/debug/jbd/jbd-debug". config JBD2 tristate diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index e7204d71acc9..45f5992a0957 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c @@ -80,7 +80,7 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, *uid = current->uid; *gid = current->gid; - *pgrp = process_group(current); + *pgrp = task_pgrp_nr(current); *minproto = *maxproto = AUTOFS_PROTO_VERSION; diff --git a/fs/autofs/root.c b/fs/autofs/root.c index c1489533277a..5efff3c0d886 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -214,8 +214,8 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr oz_mode = autofs_oz_mode(sbi); DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, " - "oz_mode = %d\n", pid_nr(task_pid(current)), - process_group(current), sbi->catatonic, + "oz_mode = %d\n", task_pid_nr(current), + task_pgrp_nr(current), sbi->catatonic, oz_mode)); /* @@ -536,7 +536,7 @@ static int autofs_root_ioctl(struct inode *inode, struct file *filp, struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb); void __user *argp = (void __user *)arg; - DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,process_group(current))); + DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,task_pgrp_nr(current))); if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT) diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index d85f42fa9206..2d4ae40718d9 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -131,7 +131,7 @@ static inline struct autofs_info *autofs4_dentry_ino(struct dentry *dentry) filesystem without "magic".) */ static inline int autofs4_oz_mode(struct autofs_sb_info *sbi) { - return sbi->catatonic || process_group(current) == sbi->oz_pgrp; + return sbi->catatonic || task_pgrp_nr(current) == sbi->oz_pgrp; } /* Does a dentry have some pending activity? */ diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index cd81f0836671..7f05d6ccdb13 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -226,7 +226,7 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, *uid = current->uid; *gid = current->gid; - *pgrp = process_group(current); + *pgrp = task_pgrp_nr(current); *minproto = AUTOFS_MIN_PROTO_VERSION; *maxproto = AUTOFS_MAX_PROTO_VERSION; @@ -323,7 +323,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) sbi->pipe = NULL; sbi->catatonic = 1; sbi->exp_timeout = 0; - sbi->oz_pgrp = process_group(current); + sbi->oz_pgrp = task_pgrp_nr(current); sbi->sb = s; sbi->version = 0; sbi->sub_version = 0; diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 45ff3d63b758..2bbcc8151dc3 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -582,7 +582,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s oz_mode = autofs4_oz_mode(sbi); DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", - current->pid, process_group(current), sbi->catatonic, oz_mode); + current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); unhashed = autofs4_lookup_unhashed(sbi, dentry->d_parent, &dentry->d_name); if (!unhashed) { @@ -976,7 +976,7 @@ static int autofs4_root_ioctl(struct inode *inode, struct file *filp, void __user *p = (void __user *)arg; DPRINTK("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u", - cmd,arg,sbi,process_group(current)); + cmd,arg,sbi,task_pgrp_nr(current)); if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 6e2f3b8dde7f..ba8de7ca260b 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1383,10 +1383,10 @@ static void fill_prstatus(struct elf_prstatus *prstatus, prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; prstatus->pr_sigpend = p->pending.signal.sig[0]; prstatus->pr_sighold = p->blocked.sig[0]; - prstatus->pr_pid = p->pid; - prstatus->pr_ppid = p->parent->pid; - prstatus->pr_pgrp = process_group(p); - prstatus->pr_sid = process_session(p); + prstatus->pr_pid = task_pid_vnr(p); + prstatus->pr_ppid = task_pid_vnr(p->parent); + prstatus->pr_pgrp = task_pgrp_vnr(p); + prstatus->pr_sid = task_session_vnr(p); if (thread_group_leader(p)) { /* * This is the record for the group leader. Add in the @@ -1429,10 +1429,10 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, psinfo->pr_psargs[i] = ' '; psinfo->pr_psargs[len] = 0; - psinfo->pr_pid = p->pid; - psinfo->pr_ppid = p->parent->pid; - psinfo->pr_pgrp = process_group(p); - psinfo->pr_sid = process_session(p); + psinfo->pr_pid = task_pid_vnr(p); + psinfo->pr_ppid = task_pid_vnr(p->parent); + psinfo->pr_pgrp = task_pgrp_vnr(p); + psinfo->pr_sid = task_session_vnr(p); i = p->state ? ffz(~p->state) + 1 : 0; psinfo->pr_state = i; diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 033861c6b8f1..32649f2a1654 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1342,10 +1342,10 @@ static void fill_prstatus(struct elf_prstatus *prstatus, prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; prstatus->pr_sigpend = p->pending.signal.sig[0]; prstatus->pr_sighold = p->blocked.sig[0]; - prstatus->pr_pid = p->pid; - prstatus->pr_ppid = p->parent->pid; - prstatus->pr_pgrp = process_group(p); - prstatus->pr_sid = process_session(p); + prstatus->pr_pid = task_pid_vnr(p); + prstatus->pr_ppid = task_pid_vnr(p->parent); + prstatus->pr_pgrp = task_pgrp_vnr(p); + prstatus->pr_sid = task_session_vnr(p); if (thread_group_leader(p)) { /* * This is the record for the group leader. Add in the @@ -1391,10 +1391,10 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, psinfo->pr_psargs[i] = ' '; psinfo->pr_psargs[len] = 0; - psinfo->pr_pid = p->pid; - psinfo->pr_ppid = p->parent->pid; - psinfo->pr_pgrp = process_group(p); - psinfo->pr_sid = process_session(p); + psinfo->pr_pid = task_pid_vnr(p); + psinfo->pr_ppid = task_pid_vnr(p->parent); + psinfo->pr_pgrp = task_pgrp_vnr(p); + psinfo->pr_sid = task_session_vnr(p); i = p->state ? ffz(~p->state) + 1 : 0; psinfo->pr_state = i; diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index bed6215c0794..3d419163c3d3 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,19 @@ +Version 1.51 +------------ +Fix memory leak in statfs when mounted to very old servers (e.g. +Windows 9x). Add new feature "POSIX open" which allows servers +which support the current POSIX Extensions to provide better semantics +(e.g. delete for open files opened with posix open). Take into +account umask on posix mkdir not just older style mkdir. Add +ability to mount to IPC$ share (which allows CIFS named pipes to be +opened, read and written as if they were files). When 1st tree +connect fails (e.g. due to signing negotiation failure) fix +leak that causes cifsd not to stop and rmmod to fail to cleanup +cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on +bigendian architectures. Fix possible memory corruption when +EAGAIN returned on kern_recvmsg. Return better error if server +requires packet signing but client has disabled it. + Version 1.50 ------------ Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is @@ -6,7 +22,10 @@ done with "serverino" mount option). Add support for POSIX Unlink Samba supports newer POSIX CIFS Protocol Extensions). Add "nounix" mount option to allow disabling the CIFS Unix Extensions for just that mount. Fix hang on spinlock in find_writable_file (race when -reopening file after session crash). +reopening file after session crash). Byte range unlock request to +windows server could unlock more bytes (on server copy of file) +than intended if start of unlock request is well before start of +a previous byte range lock that we issued. Version 1.49 ------------ diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 6ecd9d6ba3f3..ff6ba8d823f0 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -3,4 +3,4 @@ # obj-$(CONFIG_CIFS) += cifs.o -cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o export.o +cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o export.o cifsacl.o diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index f50a88d58f78..2a01f3ef96a0 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -385,10 +385,9 @@ asn1_oid_decode(struct asn1_ctx *ctx, unsigned long *optr; size = eoc - ctx->pointer + 1; - *oid = kmalloc(size * sizeof (unsigned long), GFP_ATOMIC); - if (*oid == NULL) { + *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); + if (*oid == NULL) return 0; - } optr = *oid; @@ -581,9 +580,8 @@ decode_negTokenInit(unsigned char *security_blob, int length, return 0; } else if ((cls != ASN1_UNI) || (con != ASN1_CON) || (tag != ASN1_SEQ)) { - cFYI(1, - ("Exit 6 cls = %d con = %d tag = %d end = %p (%d)", - cls, con, tag, end, *end)); + cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)", + cls, con, tag, end, *end)); } if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 1bf8cf522ad6..73c4c419663c 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -209,13 +209,16 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, i++; tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); - length = - sprintf(buf, - "\n%d) %s Uses: %d Type: %s DevInfo: 0x%x " - "Attributes: 0x%x\nPathComponentMax: %d Status: %d", - i, tcon->treeName, - atomic_read(&tcon->useCount), - tcon->nativeFileSystem, + length = sprintf(buf, "\n%d) %s Uses: %d ", i, + tcon->treeName, atomic_read(&tcon->useCount)); + buf += length; + if (tcon->nativeFileSystem) { + length = sprintf(buf, "Type: %s ", + tcon->nativeFileSystem); + buf += length; + } + length = sprintf(buf, "DevInfo: 0x%x Attributes: 0x%x" + "\nPathComponentMax: %d Status: %d", le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), le32_to_cpu(tcon->fsAttrInfo.Attributes), le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), @@ -876,11 +879,16 @@ security_flags_write(struct file *file, const char __user *buffer, if (count < 3) { /* single char or single char followed by null */ c = flags_string[0]; - if (c == '0' || c == 'n' || c == 'N') + if (c == '0' || c == 'n' || c == 'N') { extended_security = CIFSSEC_DEF; /* default */ - else if (c == '1' || c == 'y' || c == 'Y') + return count; + } else if (c == '1' || c == 'y' || c == 'Y') { extended_security = CIFSSEC_MAX; - return count; + return count; + } else if (!isdigit(c)) { + cERROR(1, ("invalid flag %c", c)); + return -EINVAL; + } } /* else we have a number */ diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c new file mode 100644 index 000000000000..e8e56353f5a1 --- /dev/null +++ b/fs/cifs/cifsacl.c @@ -0,0 +1,333 @@ +/* + * fs/cifs/cifsacl.c + * + * Copyright (C) International Business Machines Corp., 2007 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * Contains the routines for mapping CIFS/NTFS ACLs + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/fs.h> +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsacl.h" +#include "cifsproto.h" +#include "cifs_debug.h" + + +#ifdef CONFIG_CIFS_EXPERIMENTAL + +static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { + {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, + {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, + {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"}, + {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(18), 0, 0, 0, 0} }, "sys"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(544), 0, 0, 0} }, "root"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(545), 0, 0, 0} }, "users"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"} +}; + + +/* security id for everyone */ +static const struct cifs_sid sid_everyone = + {1, 1, {0, 0, 0, 0, 0, 0}, {} }; +/* group users */ +static const struct cifs_sid sid_user = + {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; + + +int match_sid(struct cifs_sid *ctsid) +{ + int i, j; + int num_subauth, num_sat, num_saw; + struct cifs_sid *cwsid; + + if (!ctsid) + return (-1); + + for (i = 0; i < NUM_WK_SIDS; ++i) { + cwsid = &(wksidarr[i].cifssid); + + /* compare the revision */ + if (ctsid->revision != cwsid->revision) + continue; + + /* compare all of the six auth values */ + for (j = 0; j < 6; ++j) { + if (ctsid->authority[j] != cwsid->authority[j]) + break; + } + if (j < 6) + continue; /* all of the auth values did not match */ + + /* compare all of the subauth values if any */ + num_sat = ctsid->num_subauth; + num_saw = cwsid->num_subauth; + num_subauth = num_sat < num_saw ? num_sat : num_saw; + if (num_subauth) { + for (j = 0; j < num_subauth; ++j) { + if (ctsid->sub_auth[j] != cwsid->sub_auth[j]) + break; + } + if (j < num_subauth) + continue; /* all sub_auth values do not match */ + } + + cFYI(1, ("matching sid: %s\n", wksidarr[i].sidname)); + return (0); /* sids compare/match */ + } + + cFYI(1, ("No matching sid")); + return (-1); +} + +/* if the two SIDs (roughly equivalent to a UUID for a user or group) are + the same returns 1, if they do not match returns 0 */ +int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid) +{ + int i; + int num_subauth, num_sat, num_saw; + + if ((!ctsid) || (!cwsid)) + return (0); + + /* compare the revision */ + if (ctsid->revision != cwsid->revision) + return (0); + + /* compare all of the six auth values */ + for (i = 0; i < 6; ++i) { + if (ctsid->authority[i] != cwsid->authority[i]) + return (0); + } + + /* compare all of the subauth values if any */ + num_sat = ctsid->num_subauth; + num_saw = cwsid->num_subauth; + num_subauth = num_sat < num_saw ? num_sat : num_saw; + if (num_subauth) { + for (i = 0; i < num_subauth; ++i) { + if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) + return (0); + } + } + + return (1); /* sids compare/match */ +} + + +static void parse_ace(struct cifs_ace *pace, char *end_of_acl) +{ + int num_subauth; + + /* validate that we do not go past end of acl */ + + /* XXX this if statement can be removed + if (end_of_acl < (char *)pace + sizeof(struct cifs_ace)) { + cERROR(1, ("ACL too small to parse ACE")); + return; + } */ + + num_subauth = pace->num_subauth; + if (num_subauth) { +#ifdef CONFIG_CIFS_DEBUG2 + int i; + cFYI(1, ("ACE revision %d num_subauth %d", + pace->revision, pace->num_subauth)); + for (i = 0; i < num_subauth; ++i) { + cFYI(1, ("ACE sub_auth[%d]: 0x%x", i, + le32_to_cpu(pace->sub_auth[i]))); + } + + /* BB add length check to make sure that we do not have huge + num auths and therefore go off the end */ + + cFYI(1, ("RID %d", le32_to_cpu(pace->sub_auth[num_subauth-1]))); +#endif + } + + return; +} + +static void parse_ntace(struct cifs_ntace *pntace, char *end_of_acl) +{ + /* validate that we do not go past end of acl */ + if (end_of_acl < (char *)pntace + sizeof(struct cifs_ntace)) { + cERROR(1, ("ACL too small to parse NT ACE")); + return; + } + +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("NTACE type %d flags 0x%x size %d, access Req 0x%x", + pntace->type, pntace->flags, pntace->size, + pntace->access_req)); +#endif + return; +} + + + +static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, + struct cifs_sid *pownersid, struct cifs_sid *pgrpsid) +{ + int i; + int num_aces = 0; + int acl_size; + char *acl_base; + struct cifs_ntace **ppntace; + struct cifs_ace **ppace; + + /* BB need to add parm so we can store the SID BB */ + + /* validate that we do not go past end of acl */ + if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { + cERROR(1, ("ACL too small to parse DACL")); + return; + } + +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("DACL revision %d size %d num aces %d", + le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), + le32_to_cpu(pdacl->num_aces))); +#endif + + acl_base = (char *)pdacl; + acl_size = sizeof(struct cifs_acl); + + num_aces = le32_to_cpu(pdacl->num_aces); + if (num_aces > 0) { + ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *), + GFP_KERNEL); + ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), + GFP_KERNEL); + +/* cifscred->cecount = pdacl->num_aces; + cifscred->ntaces = kmalloc(num_aces * + sizeof(struct cifs_ntace *), GFP_KERNEL); + cifscred->aces = kmalloc(num_aces * + sizeof(struct cifs_ace *), GFP_KERNEL);*/ + + for (i = 0; i < num_aces; ++i) { + ppntace[i] = (struct cifs_ntace *) + (acl_base + acl_size); + ppace[i] = (struct cifs_ace *) ((char *)ppntace[i] + + sizeof(struct cifs_ntace)); + + parse_ntace(ppntace[i], end_of_acl); + if (end_of_acl < ((char *)ppace[i] + + (le16_to_cpu(ppntace[i]->size) - + sizeof(struct cifs_ntace)))) { + cERROR(1, ("ACL too small to parse ACE")); + break; + } else + parse_ace(ppace[i], end_of_acl); + +/* memcpy((void *)(&(cifscred->ntaces[i])), + (void *)ppntace[i], + sizeof(struct cifs_ntace)); + memcpy((void *)(&(cifscred->aces[i])), + (void *)ppace[i], + sizeof(struct cifs_ace)); */ + + acl_base = (char *)ppntace[i]; + acl_size = le16_to_cpu(ppntace[i]->size); + } + + kfree(ppace); + kfree(ppntace); + } + + return; +} + + +static int parse_sid(struct cifs_sid *psid, char *end_of_acl) +{ + + /* BB need to add parm so we can store the SID BB */ + + /* validate that we do not go past end of acl */ + if (end_of_acl < (char *)psid + sizeof(struct cifs_sid)) { + cERROR(1, ("ACL too small to parse SID")); + return -EINVAL; + } + + if (psid->num_subauth) { +#ifdef CONFIG_CIFS_DEBUG2 + int i; + cFYI(1, ("SID revision %d num_auth %d First subauth 0x%x", + psid->revision, psid->num_subauth, psid->sub_auth[0])); + + for (i = 0; i < psid->num_subauth; i++) { + cFYI(1, ("SID sub_auth[%d]: 0x%x ", i, + le32_to_cpu(psid->sub_auth[i]))); + } + + /* BB add length check to make sure that we do not have huge + num auths and therefore go off the end */ + cFYI(1, ("RID 0x%x", + le32_to_cpu(psid->sub_auth[psid->num_subauth-1]))); +#endif + } + + return 0; +} + + +/* Convert CIFS ACL to POSIX form */ +int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) +{ + int rc; + struct cifs_sid *owner_sid_ptr, *group_sid_ptr; + struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ + char *end_of_acl = ((char *)pntsd) + acl_len; + + owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + + le32_to_cpu(pntsd->osidoffset)); + group_sid_ptr = (struct cifs_sid *)((char *)pntsd + + le32_to_cpu(pntsd->gsidoffset)); + dacl_ptr = (struct cifs_acl *)((char *)pntsd + + le32_to_cpu(pntsd->dacloffset)); +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x " + "sacloffset 0x%x dacloffset 0x%x", + pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), + le32_to_cpu(pntsd->gsidoffset), + le32_to_cpu(pntsd->sacloffset), + le32_to_cpu(pntsd->dacloffset))); +#endif + rc = parse_sid(owner_sid_ptr, end_of_acl); + if (rc) + return rc; + + rc = parse_sid(group_sid_ptr, end_of_acl); + if (rc) + return rc; + + parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr); + +/* cifscred->uid = owner_sid_ptr->rid; + cifscred->gid = group_sid_ptr->rid; + memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr, + sizeof (struct cifs_sid)); + memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, + sizeof (struct cifs_sid)); */ + + + return (0); +} +#endif /* CONFIG_CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 5eff35d6e564..420f87813647 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifsacl.h * - * Copyright (c) International Business Machines Corp., 2005 + * Copyright (c) International Business Machines Corp., 2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -22,17 +22,65 @@ #ifndef _CIFSACL_H #define _CIFSACL_H + +#define NUM_AUTHS 6 /* number of authority fields */ +#define NUM_SUBAUTHS 5 /* number of sub authority fields */ +#define NUM_WK_SIDS 7 /* number of well known sids */ +#define SIDNAMELENGTH 20 /* long enough for the ones we care about */ + +#define READ_BIT 0x4 +#define WRITE_BIT 0x2 +#define EXEC_BIT 0x1 + +#define UBITSHIFT 6 +#define GBITSHIFT 3 + +struct cifs_ntsd { + __le16 revision; /* revision level */ + __le16 type; + __le32 osidoffset; + __le32 gsidoffset; + __le32 sacloffset; + __le32 dacloffset; +} __attribute__((packed)); + struct cifs_sid { __u8 revision; /* revision level */ - __u8 num_subauths; + __u8 num_subauth; + __u8 authority[6]; + __le32 sub_auth[5]; /* sub_auth[num_subauth] */ /* BB FIXME endianness BB */ +} __attribute__((packed)); + +struct cifs_acl { + __le16 revision; /* revision level */ + __le16 size; + __le32 num_aces; +} __attribute__((packed)); + +struct cifs_ntace { /* first part of ACE which contains perms */ + __u8 type; + __u8 flags; + __le16 size; + __le32 access_req; +} __attribute__((packed)); + +struct cifs_ace { /* last part of ACE which includes user info */ + __u8 revision; /* revision level */ + __u8 num_subauth; __u8 authority[6]; - __u32 sub_auth[4]; - /* next sub_auth if any ... */ + __le32 sub_auth[5]; } __attribute__((packed)); -/* everyone */ -/* extern const struct cifs_sid sid_everyone;*/ -/* group users */ -/* extern const struct cifs_sid sid_user;*/ +struct cifs_wksid { + struct cifs_sid cifssid; + char sidname[SIDNAMELENGTH]; +} __attribute__((packed)); + +#ifdef CONFIG_CIFS_EXPERIMENTAL + +extern int match_sid(struct cifs_sid *); +extern int compare_sids(struct cifs_sid *, struct cifs_sid *); + +#endif /* CONFIG_CIFS_EXPERIMENTAL */ #endif /* _CIFSACL_H */ diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 36272293027d..632070b4275d 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -345,7 +345,7 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, user = kmalloc(2 + (len * 2), GFP_KERNEL); if (user == NULL) goto calc_exit_2; - len = cifs_strtoUCS(user, ses->userName, len, nls_cp); + len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); UniStrupr(user); hmac_md5_update((char *)user, 2*len, pctxt); @@ -356,7 +356,8 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, domain = kmalloc(2 + (len * 2), GFP_KERNEL); if (domain == NULL) goto calc_exit_1; - len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp); + len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, + nls_cp); /* the following line was removed since it didn't work well with lower cased domain name that passed as an option. Maybe converting the domain name earlier makes sense */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ba8f7868cb23..a6fbea57c4b1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -49,10 +49,6 @@ static struct quotactl_ops cifs_quotactl_ops; #endif /* QUOTA */ -#ifdef CONFIG_CIFS_EXPERIMENTAL -extern struct export_operations cifs_export_ops; -#endif /* EXPERIMENTAL */ - int cifsFYI = 0; int cifsERROR = 1; int traceSMB = 0; @@ -240,9 +236,9 @@ static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd) cifs_sb = CIFS_SB(inode->i_sb); - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) return 0; - } else /* file mode might have been restricted at mount time + else /* file mode might have been restricted at mount time on the client (above and beyond ACL on servers) for servers which do not support setting and viewing mode bits, so allowing client to check permissions is useful */ @@ -312,15 +308,15 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) seq_printf(s, ",domain=%s", cifs_sb->tcon->ses->domainName); } + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) || + !(cifs_sb->tcon->unix_ext)) + seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || + !(cifs_sb->tcon->unix_ext)) + seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); } if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) seq_printf(s, ",posixpaths"); - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) || - !(cifs_sb->tcon->unix_ext)) - seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || - !(cifs_sb->tcon->unix_ext)) - seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); seq_printf(s, ",rsize=%d", cifs_sb->rsize); seq_printf(s, ",wsize=%d", cifs_sb->wsize); } @@ -346,7 +342,7 @@ int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid, if (pTcon) { cFYI(1, ("set type: 0x%x id: %d", quota_type, qid)); } else { - return -EIO; + rc = -EIO; } FreeXid(xid); @@ -716,7 +712,7 @@ static int cifs_init_inodecache(void) { cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", - sizeof (struct cifsInodeInfo), + sizeof(struct cifsInodeInfo), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), cifs_init_once); @@ -816,8 +812,8 @@ static int cifs_init_mids(void) { cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", - sizeof (struct mid_q_entry), 0, - SLAB_HWCACHE_ALIGN, NULL); + sizeof(struct mid_q_entry), 0, + SLAB_HWCACHE_ALIGN, NULL); if (cifs_mid_cachep == NULL) return -ENOMEM; @@ -829,8 +825,8 @@ cifs_init_mids(void) } cifs_oplock_cachep = kmem_cache_create("cifs_oplock_structs", - sizeof (struct oplock_q_entry), 0, - SLAB_HWCACHE_ALIGN, NULL); + sizeof(struct oplock_q_entry), 0, + SLAB_HWCACHE_ALIGN, NULL); if (cifs_oplock_cachep == NULL) { mempool_destroy(cifs_mid_poolp); kmem_cache_destroy(cifs_mid_cachep); @@ -882,7 +878,8 @@ static int cifs_oplock_thread(void *dummyarg) the call */ /* mutex_lock(&inode->i_mutex);*/ if (S_ISREG(inode->i_mode)) { - rc = filemap_fdatawrite(inode->i_mapping); + rc = + filemap_fdatawrite(inode->i_mapping); if (CIFS_I(inode)->clientCanCacheRead == 0) { filemap_fdatawait(inode->i_mapping); @@ -907,8 +904,7 @@ static int cifs_oplock_thread(void *dummyarg) 0 /* len */ , 0 /* offset */, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, 0 /* wait flag */); - cFYI(1, - ("Oplock release rc = %d ", rc)); + cFYI(1, ("Oplock release rc = %d", rc)); } } else spin_unlock(&GlobalMid_Lock); diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index a20de77a3856..0a3ee5a322b0 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifsfs.h * - * Copyright (c) International Business Machines Corp., 2002, 2005 + * Copyright (c) International Business Machines Corp., 2002, 2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -99,7 +99,12 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *, size_t, int); extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); -extern int cifs_ioctl (struct inode *inode, struct file *filep, +extern int cifs_ioctl(struct inode *inode, struct file *filep, unsigned int command, unsigned long arg); -#define CIFS_VERSION "1.50" + +#ifdef CONFIG_CIFS_EXPERIMENTAL +extern struct export_operations cifs_export_ops; +#endif /* EXPERIMENTAL */ + +#define CIFS_VERSION "1.51" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b98742fc3b5a..87f51f23276f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -19,6 +19,7 @@ #include <linux/in.h> #include <linux/in6.h> #include "cifs_fs_sb.h" +#include "cifsacl.h" /* * The sizes of various internal tables and strings */ @@ -89,7 +90,8 @@ enum statusEnum { }; enum securityEnum { - LANMAN = 0, /* Legacy LANMAN auth */ + PLAINTXT = 0, /* Legacy with Plaintext passwords */ + LANMAN, /* Legacy LANMAN auth */ NTLM, /* Legacy NTLM012 auth with NTLM hash */ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ RawNTLMSSP, /* NTLMSSP without SPNEGO */ @@ -115,6 +117,17 @@ struct mac_key { } data; }; +struct cifs_cred { + int uid; + int gid; + int mode; + int cecount; + struct cifs_sid osid; + struct cifs_sid gsid; + struct cifs_ntace *ntaces; + struct cifs_ace *aces; +}; + /* ***************************************************************** * Except the CIFS PDUs themselves all the @@ -279,6 +292,7 @@ struct cifsTconInfo { FILE_SYSTEM_DEVICE_INFO fsDevInfo; FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ FILE_SYSTEM_UNIX_INFO fsUnixInfo; + unsigned ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */ unsigned retry:1; unsigned nocase:1; unsigned unix_ext:1; /* if off disable Linux extensions to CIFS protocol @@ -329,6 +343,7 @@ struct cifsFileInfo { struct list_head llist; /* list of byte range locks we have. */ unsigned closePend:1; /* file is marked to close */ unsigned invalidHandle:1; /* file closed via session abend */ + unsigned messageMode:1; /* for pipes: message vs byte mode */ atomic_t wrtPending; /* handle in use - defer close */ struct semaphore fh_sem; /* prevents reopen race after dead ses*/ char *search_resume_name; /* BB removeme BB */ @@ -464,6 +479,9 @@ struct dir_notify_req { #ifdef CONFIG_CIFS_WEAK_PW_HASH #define CIFSSEC_MAY_LANMAN 0x00010 #define CIFSSEC_MAY_PLNTXT 0x00020 +#else +#define CIFSSEC_MAY_LANMAN 0 +#define CIFSSEC_MAY_PLNTXT 0 #endif /* weak passwords */ #define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ @@ -477,14 +495,23 @@ require use of the stronger protocol */ #ifdef CONFIG_CIFS_WEAK_PW_HASH #define CIFSSEC_MUST_LANMAN 0x10010 #define CIFSSEC_MUST_PLNTXT 0x20020 +#ifdef CONFIG_CIFS_UPCALL +#define CIFSSEC_MASK 0x3F03F /* allows weak security but also krb5 */ +#else #define CIFSSEC_MASK 0x37037 /* current flags supported if weak */ +#endif /* UPCALL */ +#else /* do not allow weak pw hash */ +#ifdef CONFIG_CIFS_UPCALL +#define CIFSSEC_MASK 0x0F00F /* flags supported if no weak allowed */ #else -#define CIFSSEC_MASK 0x07007 /* flags supported if no weak config */ +#define CIFSSEC_MASK 0x07007 /* flags supported if no weak allowed */ +#endif /* UPCALL */ #endif /* WEAK_PW_HASH */ #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ #define CIFSSEC_DEF CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 #define CIFSSEC_MAX CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2 +#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5) /* ***************************************************************** * All constants go here diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 6a2056e58ceb..c41ff74e9128 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -215,6 +215,12 @@ /* file_execute, file_read_attributes*/ /* write_dac, and delete. */ +#define FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES) +#define FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \ + | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) +#define FILE_EXEC_RIGHTS (FILE_EXECUTE) + + /* * Invalid readdir handle */ @@ -360,10 +366,10 @@ struct smb_hdr { __u8 WordCount; } __attribute__((packed)); /* given a pointer to an smb_hdr retrieve the value of byte count */ -#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) -#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) +#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) +#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ -#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) +#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount) + 2) /* * Computer Name Length (since Netbios name was length 16 with last byte 0x20) @@ -716,6 +722,14 @@ typedef struct smb_com_findclose_req { #define REQ_OPENDIRONLY 0x00000008 #define REQ_EXTENDED_INFO 0x00000010 +/* File type */ +#define DISK_TYPE 0x0000 +#define BYTE_PIPE_TYPE 0x0001 +#define MESSAGE_PIPE_TYPE 0x0002 +#define PRINTER_TYPE 0x0003 +#define COMM_DEV_TYPE 0x0004 +#define UNKNOWN_TYPE 0xFFFF + typedef struct smb_com_open_req { /* also handles create */ struct smb_hdr hdr; /* wct = 24 */ __u8 AndXCommand; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 04a69dafedba..1a883663b22d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -50,7 +50,8 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, int * /* bytes returned */ , const int long_op); extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, struct kvec *, int /* nvec to send */, - int * /* type of buf returned */ , const int long_op); + int * /* type of buf returned */ , const int long_op, + const int logError /* whether to log status code*/ ); extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *, struct smb_hdr * /* input */ , @@ -65,7 +66,7 @@ extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, enum securityEnum *secType); extern int cifs_inet_pton(int, char *source, void *dst); -extern int map_smb_to_linux_error(struct smb_hdr *smb); +extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); extern void header_assemble(struct smb_hdr *, char /* command */ , const struct cifsTconInfo *, int /* length of fixed section (word count) in two byte units */); @@ -304,12 +305,13 @@ extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn, const char *pass); extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, const struct nls_table *); -extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * ); +extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, const struct nls_table *); #ifdef CONFIG_CIFS_WEAK_PW_HASH extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ +extern int parse_sec_desc(struct cifs_ntsd *, int); extern int CIFSSMBCopy(int xid, struct cifsTconInfo *source_tcon, const char *fromName, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 8eb102f940d4..f0d9a485d095 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -34,10 +34,10 @@ #include <asm/uaccess.h> #include "cifspdu.h" #include "cifsglob.h" +#include "cifsacl.h" #include "cifsproto.h" #include "cifs_unicode.h" #include "cifs_debug.h" -#include "cifsacl.h" #ifdef CONFIG_CIFS_POSIX static struct { @@ -94,9 +94,8 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon) write_lock(&GlobalSMBSeslock); list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, tlist); - if (open_file) { + if (open_file) open_file->invalidHandle = TRUE; - } } write_unlock(&GlobalSMBSeslock); /* BB Add call to invalidate_inodes(sb) for all superblocks mounted @@ -439,8 +438,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) pSMB->hdr.Mid = GetNextMid(server); pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); + if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; + else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { + cFYI(1, ("Kerberos only mechanism, enable extended security")); + pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; + } count = 0; for (i = 0; i < CIFS_NUM_PROT; i++) { @@ -513,7 +517,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) (int)ts.tv_sec, (int)utc.tv_sec, (int)(utc.tv_sec - ts.tv_sec))); val = (int)(utc.tv_sec - ts.tv_sec); - seconds = val < 0 ? -val : val; + seconds = abs(val); result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; remain = seconds % MIN_TZ_ADJ; if (remain >= (MIN_TZ_ADJ / 2)) @@ -574,7 +578,20 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->secType = NTLM; else if (secFlags & CIFSSEC_MAY_NTLMV2) server->secType = NTLMv2; - /* else krb5 ... any others ... */ + else if (secFlags & CIFSSEC_MAY_KRB5) + server->secType = Kerberos; + else if (secFlags & CIFSSEC_MAY_LANMAN) + server->secType = LANMAN; +/* #ifdef CONFIG_CIFS_EXPERIMENTAL + else if (secFlags & CIFSSEC_MAY_PLNTXT) + server->secType = ?? +#endif */ + else { + rc = -EOPNOTSUPP; + cERROR(1, ("Invalid security type")); + goto neg_err_exit; + } + /* else ... any others ...? */ /* one byte, so no need to convert this or EncryptionKeyLen from little endian */ @@ -604,22 +621,26 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && (server->capabilities & CAP_EXTENDED_SECURITY)) { count = pSMBr->ByteCount; - if (count < 16) + if (count < 16) { rc = -EIO; - else if (count == 16) { - server->secType = RawNTLMSSP; - if (server->socketUseCount.counter > 1) { - if (memcmp(server->server_GUID, - pSMBr->u.extended_response. - GUID, 16) != 0) { - cFYI(1, ("server UID changed")); - memcpy(server->server_GUID, - pSMBr->u.extended_response.GUID, - 16); - } - } else + goto neg_err_exit; + } + + if (server->socketUseCount.counter > 1) { + if (memcmp(server->server_GUID, + pSMBr->u.extended_response. + GUID, 16) != 0) { + cFYI(1, ("server UID changed")); memcpy(server->server_GUID, - pSMBr->u.extended_response.GUID, 16); + pSMBr->u.extended_response.GUID, + 16); + } + } else + memcpy(server->server_GUID, + pSMBr->u.extended_response.GUID, 16); + + if (count == 16) { + server->secType = RawNTLMSSP; } else { rc = decode_negTokenInit(pSMBr->u.extended_response. SecurityBlob, @@ -642,10 +663,12 @@ signing_check: /* MUST_SIGN already includes the MAY_SIGN FLAG so if this is zero it means that signing is disabled */ cFYI(1, ("Signing disabled")); - if (server->secMode & SECMODE_SIGN_REQUIRED) + if (server->secMode & SECMODE_SIGN_REQUIRED) { cERROR(1, ("Server requires " - "/proc/fs/cifs/PacketSigningEnabled " - "to be on")); + "packet signing to be enabled in " + "/proc/fs/cifs/SecurityFlags.")); + rc = -EOPNOTSUPP; + } server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) { @@ -1052,7 +1075,7 @@ PsxCreat: InformationLevel) - 4; offset = param_offset + params; pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset); - pdata->Level = SMB_QUERY_FILE_UNIX_BASIC; + pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pdata->Permissions = cpu_to_le64(mode); pdata->PosixOpenFlags = cpu_to_le32(posix_flags); pdata->OpenFlags = cpu_to_le32(*pOplock); @@ -1098,8 +1121,8 @@ PsxCreat: if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction) *pOplock |= CIFS_CREATE_ACTION; /* check to make sure response data is there */ - if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) { - pRetData->Type = -1; /* unknown */ + if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) { + pRetData->Type = cpu_to_le32(-1); /* unknown */ #ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("unknown type")); #endif @@ -1107,12 +1130,12 @@ PsxCreat: if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP) + sizeof(FILE_UNIX_BASIC_INFO)) { cERROR(1, ("Open response data too small")); - pRetData->Type = -1; + pRetData->Type = cpu_to_le32(-1); goto psx_create_err; } memcpy((char *) pRetData, (char *)psx_rsp + sizeof(OPEN_PSX_RSP), - sizeof (FILE_UNIX_BASIC_INFO)); + sizeof(FILE_UNIX_BASIC_INFO)); } psx_create_err: @@ -1193,9 +1216,9 @@ OldOpenRetry: } if (*pOplock & REQ_OPLOCK) pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK); - else if (*pOplock & REQ_BATCHOPLOCK) { + else if (*pOplock & REQ_BATCHOPLOCK) pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); - } + pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */ /* 0 = read @@ -1310,9 +1333,8 @@ openRetry: } if (*pOplock & REQ_OPLOCK) pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK); - else if (*pOplock & REQ_BATCHOPLOCK) { + else if (*pOplock & REQ_BATCHOPLOCK) pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); - } pSMB->DesiredAccess = cpu_to_le32(access_flags); pSMB->AllocationSize = 0; /* set file as system file if special file such @@ -1424,9 +1446,8 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, iov[0].iov_base = (char *)pSMB; iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; - rc = SendReceive2(xid, tcon->ses, iov, - 1 /* num iovecs */, - &resp_buf_type, 0); + rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, + &resp_buf_type, 0 /* not long op */, 1 /* log err */ ); cifs_stats_inc(&tcon->num_reads); pSMBr = (READ_RSP *)iov[0].iov_base; if (rc) { @@ -1446,11 +1467,11 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, *nbytes = 0; } else { pReadData = (char *) (&pSMBr->hdr.Protocol) + - le16_to_cpu(pSMBr->DataOffset); -/* if (rc = copy_to_user(buf, pReadData, data_length)) { + le16_to_cpu(pSMBr->DataOffset); +/* if (rc = copy_to_user(buf, pReadData, data_length)) { cERROR(1,("Faulting on read rc = %d",rc)); rc = -EFAULT; - }*/ /* can not use copy_to_user when using page cache*/ + }*/ /* can not use copy_to_user when using page cache*/ if (*buf) memcpy(*buf, pReadData, data_length); } @@ -1645,7 +1666,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, - long_op); + long_op, 0 /* do not log STATUS code */ ); cifs_stats_inc(&tcon->num_writes); if (rc) { cFYI(1, ("Send error Write2 = %d", rc)); @@ -2538,7 +2559,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, cFYI(1, ("data starts after end of smb")); return -EINVAL; } else if (data_count + *ppdata > end_of_smb) { - cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p", + cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p", *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); return -EINVAL; @@ -2615,7 +2636,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, reparse_buf->TargetNameOffset + reparse_buf->TargetNameLen) > end_of_smb) { - cFYI(1,("reparse buf goes beyond SMB")); + cFYI(1, ("reparse buf beyond SMB")); rc = -EIO; goto qreparse_out; } @@ -3042,25 +3063,12 @@ GetExtAttrOut: #endif /* CONFIG_POSIX */ - -/* security id for everyone */ -static const struct cifs_sid sid_everyone = - {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; -/* group users */ -static const struct cifs_sid sid_user = - {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; - -/* Convert CIFS ACL to POSIX form */ -static int parse_sec_desc(struct cifs_sid *psec_desc, int acl_len) -{ - return 0; -} - +#ifdef CONFIG_CIFS_EXPERIMENTAL /* Get Security Descriptor (by handle) from remote server for a file or dir */ int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, /* BB fix up return info */ char *acl_inf, const int buflen, - const int acl_type /* ACCESS/DEFAULT not sure implication */) + const int acl_type) { int rc = 0; int buf_type = 0; @@ -3085,12 +3093,13 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, iov[0].iov_base = (char *)pSMB; iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; - rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0); + rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, + 0 /* not long op */, 0 /* do not log STATUS codes */ ); cifs_stats_inc(&tcon->num_acl_get); if (rc) { cFYI(1, ("Send error in QuerySecDesc = %d", rc)); } else { /* decode response */ - struct cifs_sid *psec_desc; + struct cifs_ntsd *psec_desc; __le32 * parm; int parm_len; int data_len; @@ -3105,8 +3114,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, goto qsec_out; pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base; - cERROR(1, ("smb %p parm %p data %p", - pSMBr, parm, psec_desc)); /* BB removeme BB */ + cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc)); if (le32_to_cpu(pSMBr->ParameterCount) != 4) { rc = -EIO; /* bad smb */ @@ -3115,7 +3123,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, /* BB check that data area is minimum length and as big as acl_len */ - acl_len = le32_to_cpu(*(__le32 *)parm); + acl_len = le32_to_cpu(*parm); /* BB check if (acl_len > bufsize) */ parse_sec_desc(psec_desc, acl_len); @@ -3128,6 +3136,7 @@ qsec_out: /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ return rc; } +#endif /* CONFIG_CIFS_EXPERIMENTAL */ /* Legacy Query Path Information call for lookup to old servers such as Win9x/WinME */ @@ -3363,6 +3372,9 @@ UnixQPathInfoRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { + cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n" + "Unix Extensions can be disabled on mount " + "by specifying the nosfu mount option.")); rc = -EIO; /* bad smb */ } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -3883,12 +3895,10 @@ getDFSRetry: pSMB->hdr.Mid = GetNextMid(ses->server); pSMB->hdr.Tid = ses->ipc_tid; pSMB->hdr.Uid = ses->Suid; - if (ses->capabilities & CAP_STATUS32) { + if (ses->capabilities & CAP_STATUS32) pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS; - } - if (ses->capabilities & CAP_DFS) { + if (ses->capabilities & CAP_DFS) pSMB->hdr.Flags2 |= SMBFLG2_DFS; - } if (ses->capabilities & CAP_UNICODE) { pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; @@ -4060,10 +4070,6 @@ oldQFSInfoRetry: (void **) &pSMBr); if (rc) return rc; - rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; params = 2; /* level */ pSMB->TotalDataCount = 0; @@ -4265,7 +4271,7 @@ QFSAttributeRetry: *) (((char *) &pSMBr->hdr.Protocol) + data_offset); memcpy(&tcon->fsAttrInfo, response_data, - sizeof (FILE_SYSTEM_ATTRIBUTE_INFO)); + sizeof(FILE_SYSTEM_ATTRIBUTE_INFO)); } } cifs_buf_release(pSMB); @@ -4334,7 +4340,7 @@ QFSDeviceRetry: (((char *) &pSMBr->hdr.Protocol) + data_offset); memcpy(&tcon->fsDevInfo, response_data, - sizeof (FILE_SYSTEM_DEVICE_INFO)); + sizeof(FILE_SYSTEM_DEVICE_INFO)); } } cifs_buf_release(pSMB); @@ -4402,7 +4408,7 @@ QFSUnixRetry: *) (((char *) &pSMBr->hdr.Protocol) + data_offset); memcpy(&tcon->fsUnixInfo, response_data, - sizeof (FILE_SYSTEM_UNIX_INFO)); + sizeof(FILE_SYSTEM_UNIX_INFO)); } } cifs_buf_release(pSMB); @@ -4612,7 +4618,7 @@ SetEOFRetry: strncpy(pSMB->FileName, fileName, name_len); } params = 6 + name_len; - data_count = sizeof (struct file_end_of_file_info); + data_count = sizeof(struct file_end_of_file_info); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(4100); pSMB->MaxSetupCount = 0; @@ -4800,7 +4806,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, data_offset = (char *) (&pSMB->hdr.Protocol) + offset; - count = sizeof (FILE_BASIC_INFO); + count = sizeof(FILE_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ pSMB->SetupCount = 1; @@ -4871,7 +4877,7 @@ SetTimesRetry: } params = 6 + name_len; - count = sizeof (FILE_BASIC_INFO); + count = sizeof(FILE_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ pSMB->MaxSetupCount = 0; @@ -4900,7 +4906,7 @@ SetTimesRetry: pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; pSMB->hdr.smb_buf_length += byte_count; - memcpy(data_offset, data, sizeof (FILE_BASIC_INFO)); + memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -5003,7 +5009,7 @@ setPermsRetry: } params = 6 + name_len; - count = sizeof (FILE_UNIX_BASIC_INFO); + count = sizeof(FILE_UNIX_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ pSMB->MaxSetupCount = 0; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 4af3588c1a96..19ee11f7f35a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -124,7 +124,7 @@ cifs_reconnect(struct TCP_Server_Info *server) struct mid_q_entry *mid_entry; spin_lock(&GlobalMid_Lock); - if ( kthread_should_stop() ) { + if (kthread_should_stop()) { /* the demux thread will exit normally next time through the loop */ spin_unlock(&GlobalMid_Lock); @@ -151,9 +151,8 @@ cifs_reconnect(struct TCP_Server_Info *server) } list_for_each(tmp, &GlobalTreeConnectionList) { tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); - if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) { + if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) tcon->tidStatus = CifsNeedReconnect; - } } read_unlock(&GlobalSMBSeslock); /* do not want to be sending data on a socket we are freeing */ @@ -187,7 +186,7 @@ cifs_reconnect(struct TCP_Server_Info *server) spin_unlock(&GlobalMid_Lock); up(&server->tcpSem); - while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood)) { + while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) { try_to_freeze(); if (server->protocolType == IPV6) { rc = ipv6_connect(&server->addr.sockAddr6, @@ -204,7 +203,7 @@ cifs_reconnect(struct TCP_Server_Info *server) } else { atomic_inc(&tcpSesReconnectCount); spin_lock(&GlobalMid_Lock); - if ( !kthread_should_stop() ) + if (!kthread_should_stop()) server->tcpStatus = CifsGood; server->sequence_number = 0; spin_unlock(&GlobalMid_Lock); @@ -352,17 +351,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) current->flags |= PF_MEMALLOC; server->tsk = current; /* save process info to wake at shutdown */ - cFYI(1, ("Demultiplex PID: %d", current->pid)); + cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current))); write_lock(&GlobalSMBSeslock); atomic_inc(&tcpSesAllocCount); length = tcpSesAllocCount.counter; write_unlock(&GlobalSMBSeslock); complete(&cifsd_complete); - if (length > 1) { - mempool_resize(cifs_req_poolp, - length + cifs_min_rcv, - GFP_KERNEL); - } + if (length > 1) + mempool_resize(cifs_req_poolp, length + cifs_min_rcv, + GFP_KERNEL); set_freezable(); while (!kthread_should_stop()) { @@ -378,7 +375,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } } else if (isLargeBuf) { /* we are reusing a dirty large buf, clear its start */ - memset(bigbuf, 0, sizeof (struct smb_hdr)); + memset(bigbuf, 0, sizeof(struct smb_hdr)); } if (smallbuf == NULL) { @@ -391,7 +388,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } /* beginning of smb buffer is cleared in our buf_get */ } else /* if existing small buf clear beginning */ - memset(smallbuf, 0, sizeof (struct smb_hdr)); + memset(smallbuf, 0, sizeof(struct smb_hdr)); isLargeBuf = FALSE; isMultiRsp = FALSE; @@ -400,11 +397,13 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) iov.iov_len = 4; smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; + pdu_length = 4; /* enough to get RFC1001 header */ +incomplete_rcv: length = kernel_recvmsg(csocket, &smb_msg, - &iov, 1, 4, 0 /* BB see socket.h flags */); + &iov, 1, pdu_length, 0 /* BB other flags? */); - if ( kthread_should_stop() ) { + if (kthread_should_stop()) { break; } else if (server->tcpStatus == CifsNeedReconnect) { cFYI(1, ("Reconnect after server stopped responding")); @@ -416,7 +415,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) msleep(1); /* minimum sleep to prevent looping allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung */ - continue; + if (pdu_length < 4) + goto incomplete_rcv; + else + continue; } else if (length <= 0) { if (server->tcpStatus == CifsNew) { cFYI(1, ("tcp session abend after SMBnegprot")); @@ -437,13 +439,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) wake_up(&server->response_q); continue; } else if (length < 4) { - cFYI(1, - ("Frame under four bytes received (%d bytes long)", + cFYI(1, ("less than four bytes received (%d bytes)", length)); - cifs_reconnect(server); - csocket = server->ssocket; - wake_up(&server->response_q); - continue; + pdu_length -= length; + msleep(1); + goto incomplete_rcv; } /* The right amount was read from socket - 4 bytes */ @@ -504,7 +504,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) /* else we have an SMB response */ if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || - (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { + (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) { cERROR(1, ("Invalid size SMB length %d pdu_length %d", length, pdu_length+4)); cifs_reconnect(server); @@ -528,7 +528,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) total_read += length) { length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length - total_read, 0); - if ( kthread_should_stop() || + if (kthread_should_stop() || (length == -EINTR)) { /* then will exit */ reconnect = 2; @@ -546,6 +546,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung*/ + length = 0; continue; } else if (length <= 0) { cERROR(1, ("Received no data, expecting %d", @@ -631,9 +632,9 @@ multi_t2_fnd: /* Was previous buf put in mpx struct for multi-rsp? */ if (!isMultiRsp) { /* smb buffer will be freed by user thread */ - if (isLargeBuf) { + if (isLargeBuf) bigbuf = NULL; - } else + else smallbuf = NULL; } wake_up_process(task_to_wake); @@ -676,9 +677,8 @@ multi_t2_fnd: server->ssocket = NULL; } /* buffer usuallly freed in free_mid - need to free it here on exit */ - if (bigbuf != NULL) - cifs_buf_release(bigbuf); - if (smallbuf != NULL) + cifs_buf_release(bigbuf); + if (smallbuf) /* no sense logging a debug message if NULL */ cifs_small_buf_release(smallbuf); read_lock(&GlobalSMBSeslock); @@ -702,9 +702,8 @@ multi_t2_fnd: list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - if (ses->server == server) { + if (ses->server == server) ses->status = CifsExiting; - } } spin_lock(&GlobalMid_Lock); @@ -714,9 +713,8 @@ multi_t2_fnd: cFYI(1, ("Clearing Mid 0x%x - waking up ", mid_entry->mid)); task_to_wake = mid_entry->tsk; - if (task_to_wake) { + if (task_to_wake) wake_up_process(task_to_wake); - } } } spin_unlock(&GlobalMid_Lock); @@ -749,18 +747,15 @@ multi_t2_fnd: list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - if (ses->server == server) { + if (ses->server == server) ses->server = NULL; - } } write_unlock(&GlobalSMBSeslock); kfree(server); - if (length > 0) { - mempool_resize(cifs_req_poolp, - length + cifs_min_rcv, - GFP_KERNEL); - } + if (length > 0) + mempool_resize(cifs_req_poolp, length + cifs_min_rcv, + GFP_KERNEL); return 0; } @@ -1477,7 +1472,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, if (psin_server->sin_port) { /* user overrode default port */ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in), 0); + sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } @@ -1493,7 +1488,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in), 0); + sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } @@ -1502,7 +1497,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, psin_server->sin_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in), 0); + sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } @@ -1610,7 +1605,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) if (psin_server->sin6_port) { /* user overrode default port */ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in6), 0); + sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } @@ -1626,7 +1621,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in6), 0); + sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } @@ -1634,7 +1629,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) if (!connected) { psin_server->sin6_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) - psin_server, sizeof (struct sockaddr_in6), 0); + psin_server, sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } @@ -1750,7 +1745,16 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, cFYI(1, ("very large write cap")); #endif /* CIFS_DEBUG2 */ if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { - cFYI(1, ("setting capabilities failed")); + if (vol_info == NULL) { + cFYI(1, ("resetting capabilities failed")); + } else + cERROR(1, ("Negotiating Unix capabilities " + "with the server failed. Consider " + "mounting with the Unix Extensions\n" + "disabled, if problems are found, " + "by specifying the nounix mount " + "option.")); + } } } @@ -1909,8 +1913,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, return rc; } - srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL); - if (srvTcp == NULL) { + srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); + if (!srvTcp) { rc = -ENOMEM; sock_release(csocket); kfree(volume_info.UNC); @@ -1919,9 +1923,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, FreeXid(xid); return rc; } else { - memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); memcpy(&srvTcp->addr.sockAddr, &sin_server, - sizeof (struct sockaddr_in)); + sizeof(struct sockaddr_in)); atomic_set(&srvTcp->inFlight, 0); /* BB Add code for ipv6 case too */ srvTcp->ssocket = csocket; @@ -2173,8 +2176,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (tsk) kthread_stop(tsk); } - } else + } else { cFYI(1, ("No session or bad tcon")); + if ((pSesInfo->server) && + (pSesInfo->server->tsk)) { + struct task_struct *tsk; + force_sig(SIGKILL, + pSesInfo->server->tsk); + tsk = pSesInfo->server->tsk; + if (tsk) + kthread_stop(tsk); + } + } sesInfoFree(pSesInfo); /* pSesInfo = NULL; */ } @@ -2185,8 +2198,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, tcon->ses = pSesInfo; /* do not care if following two calls succeed - informational */ - CIFSSMBQFSDeviceInfo(xid, tcon); - CIFSSMBQFSAttributeInfo(xid, tcon); + if (!tcon->ipc) { + CIFSSMBQFSDeviceInfo(xid, tcon); + CIFSSMBQFSAttributeInfo(xid, tcon); + } /* tell server which Unix caps we support */ if (tcon->ses->capabilities & CAP_UNIX) @@ -2526,8 +2541,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, sesssetup_nomem: /* do not return an error on nomem for the info strings, since that could make reconnection harder, and reconnection might be needed to free memory */ - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } @@ -2547,7 +2561,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, int remaining_words = 0; int bytes_returned = 0; int len; - int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE); + int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE); PNEGOTIATE_MESSAGE SecurityBlob; PCHALLENGE_MESSAGE SecurityBlob2; __u32 negotiate_flags, capabilities; @@ -2865,15 +2879,14 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, rc = -EIO; } - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } static int CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *ntlm_session_key, int ntlmv2_flag, - const struct nls_table *nls_codepage) + char *ntlm_session_key, int ntlmv2_flag, + const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; struct smb_hdr *smb_buffer_response; @@ -2886,7 +2899,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, int remaining_words = 0; int bytes_returned = 0; int len; - int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE); + int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE); PAUTHENTICATE_MESSAGE SecurityBlob; __u32 negotiate_flags, capabilities; __u16 count; @@ -2901,8 +2914,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, return -ENOMEM; } smb_buffer_response = smb_buffer; - pSMB = (SESSION_SETUP_ANDX *) smb_buffer; - pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; + pSMB = (SESSION_SETUP_ANDX *)smb_buffer; + pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response; /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, @@ -2921,7 +2934,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | - CAP_EXTENDED_SECURITY; + CAP_EXTENDED_SECURITY; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; capabilities |= CAP_UNICODE; @@ -2936,15 +2949,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, } pSMB->req.Capabilities = cpu_to_le32(capabilities); - bcc_ptr = (char *) &pSMB->req.SecurityBlob; - SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr; + bcc_ptr = (char *)&pSMB->req.SecurityBlob; + SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr; strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); SecurityBlob->MessageType = NtLmAuthenticate; bcc_ptr += SecurityBlobLength; - negotiate_flags = - NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | - NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | - 0x80000000 | NTLMSSP_NEGOTIATE_128; + negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | + NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | + 0x80000000 | NTLMSSP_NEGOTIATE_128; if (sign_CIFS_PDUs) negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; if (ntlmv2_flag) @@ -2979,36 +2991,32 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { - __u16 len = - cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, + __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); - len *= 2; + ln *= 2; SecurityBlob->DomainName.MaximumLength = - cpu_to_le16(len); + cpu_to_le16(ln); SecurityBlob->DomainName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->DomainName.Length = - cpu_to_le16(len); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->DomainName.Length = cpu_to_le16(ln); } if (user == NULL) { SecurityBlob->UserName.Buffer = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { - __u16 len = - cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, + __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, nls_codepage); - len *= 2; + ln *= 2; SecurityBlob->UserName.MaximumLength = - cpu_to_le16(len); + cpu_to_le16(ln); SecurityBlob->UserName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->UserName.Length = - cpu_to_le16(len); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->UserName.Length = cpu_to_le16(ln); } /* SecurityBlob->WorkstationName.Length = @@ -3052,33 +3060,32 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { - __u16 len; + __u16 ln; negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; strncpy(bcc_ptr, domain, 63); - len = strnlen(domain, 64); + ln = strnlen(domain, 64); SecurityBlob->DomainName.MaximumLength = - cpu_to_le16(len); + cpu_to_le16(ln); SecurityBlob->DomainName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->DomainName.Length = cpu_to_le16(len); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->DomainName.Length = cpu_to_le16(ln); } if (user == NULL) { SecurityBlob->UserName.Buffer = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { - __u16 len; + __u16 ln; strncpy(bcc_ptr, user, 63); - len = strnlen(user, 64); - SecurityBlob->UserName.MaximumLength = - cpu_to_le16(len); + ln = strnlen(user, 64); + SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln); SecurityBlob->UserName.Buffer = - cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->UserName.Length = cpu_to_le16(len); + cpu_to_le32(SecurityBlobLength); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->UserName.Length = cpu_to_le16(ln); } /* BB fill in our workstation name if known BB */ @@ -3100,12 +3107,11 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &bytes_returned, 1); if (rc) { -/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ - } else if ((smb_buffer_response->WordCount == 3) - || (smb_buffer_response->WordCount == 4)) { +/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ + } else if ((smb_buffer_response->WordCount == 3) || + (smb_buffer_response->WordCount == 4)) { __u16 action = le16_to_cpu(pSMBr->resp.Action); - __u16 blob_len = - le16_to_cpu(pSMBr->resp.SecurityBlobLength); + __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); if (action & GUEST_LOGIN) cFYI(1, (" Guest login")); /* BB Should we set anything in SesInfo struct ? */ @@ -3145,8 +3151,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, } else { remaining_words = BCC(smb_buffer_response) / 2; } - len = - UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1); + len = UniStrnlen((wchar_t *) bcc_ptr, + remaining_words - 1); /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ @@ -3230,7 +3236,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, <= BCC(smb_buffer_response)) { if (ses->serverOS) kfree(ses->serverOS); - ses->serverOS = kzalloc(len + 1,GFP_KERNEL); + ses->serverOS = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; @@ -3259,28 +3265,24 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr[0] = 0; bcc_ptr++; } else - cFYI(1, - ("field of length %d " + cFYI(1, ("field of length %d " "extends beyond end of smb ", len)); } } else { - cERROR(1, - (" Security Blob extends beyond end " + cERROR(1, ("Security Blob extends beyond end " "of SMB")); } } else { cERROR(1, ("No session structure passed in.")); } } else { - cERROR(1, - (" Invalid Word count %d: ", + cERROR(1, ("Invalid Word count %d: ", smb_buffer_response->WordCount)); rc = -EIO; } - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } @@ -3389,6 +3391,18 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr = pByteArea(smb_buffer_response); length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); /* skip service field (NB: this field is always ASCII) */ + if (length == 3) { + if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && + (bcc_ptr[2] == 'C')) { + cFYI(1, ("IPC connection")); + tcon->ipc = 1; + } + } else if (length == 2) { + if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) { + /* the most common case */ + cFYI(1, ("disk share connection")); + } + } bcc_ptr += length + 1; strncpy(tcon->treeName, tree, MAX_TREE_SIZE); if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { @@ -3399,9 +3413,11 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = kzalloc(length + 2, GFP_KERNEL); - cifs_strfromUCS_le(tcon->nativeFileSystem, - (__le16 *) bcc_ptr, - length, nls_codepage); + if (tcon->nativeFileSystem) + cifs_strfromUCS_le( + tcon->nativeFileSystem, + (__le16 *) bcc_ptr, + length, nls_codepage); bcc_ptr += 2 * length; bcc_ptr[0] = 0; /* null terminate the string */ bcc_ptr[1] = 0; @@ -3416,8 +3432,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = kzalloc(length + 1, GFP_KERNEL); - strncpy(tcon->nativeFileSystem, bcc_ptr, - length); + if (tcon->nativeFileSystem) + strncpy(tcon->nativeFileSystem, bcc_ptr, + length); } /* else do not bother copying these information fields*/ } @@ -3433,8 +3450,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ses->ipc_tid = smb_buffer_response->Tid; } - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 4830acc86d74..793404b10925 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -3,7 +3,7 @@ * * vfs operations that deal with dentries * - * Copyright (C) International Business Machines Corp., 2002,2005 + * Copyright (C) International Business Machines Corp., 2002,2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -269,7 +269,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, CIFSSMBClose(xid, pTcon, fileHandle); } else if (newinode) { pCifsFile = - kzalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); + kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); if (pCifsFile == NULL) goto cifs_create_out; @@ -397,7 +397,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, /* BB Do not bother to decode buf since no local inode yet to put timestamps in, but we can reuse it safely */ - int bytes_written; + unsigned int bytes_written; struct win_dev *pdev; pdev = (struct win_dev *)buf; if (S_ISCHR(mode)) { @@ -450,8 +450,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, xid = GetXid(); - cFYI(1, - (" parent inode = 0x%p name is: %s and dentry = 0x%p", + cFYI(1, (" parent inode = 0x%p name is: %s and dentry = 0x%p", parent_dir_inode, direntry->d_name.name, direntry)); /* check whether path exists */ diff --git a/fs/cifs/export.c b/fs/cifs/export.c index 893fd0aebff8..d614b91caeca 100644 --- a/fs/cifs/export.c +++ b/fs/cifs/export.c @@ -43,6 +43,7 @@ #include <linux/exportfs.h> #include "cifsglob.h" #include "cifs_debug.h" +#include "cifsfs.h" #ifdef CONFIG_CIFS_EXPERIMENTAL static struct dentry *cifs_get_parent(struct dentry *dentry) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 894b1f7b299d..1e7e4c06d9e3 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -467,7 +467,7 @@ reopen_error_exit: int cifs_close(struct inode *inode, struct file *file) { int rc = 0; - int xid; + int xid, timeout; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; struct cifsFileInfo *pSMBFile = @@ -485,9 +485,9 @@ int cifs_close(struct inode *inode, struct file *file) /* no sense reconnecting to close a file that is already closed */ if (pTcon->tidStatus != CifsNeedReconnect) { - int timeout = 2; + timeout = 2; while ((atomic_read(&pSMBFile->wrtPending) != 0) - && (timeout < 1000) ) { + && (timeout <= 2048)) { /* Give write a better chance to get to server ahead of the close. We do not want to add a wait_q here as it would @@ -522,12 +522,30 @@ int cifs_close(struct inode *inode, struct file *file) list_del(&pSMBFile->flist); list_del(&pSMBFile->tlist); write_unlock(&GlobalSMBSeslock); + timeout = 10; + /* We waited above to give the SMBWrite a chance to issue + on the wire (so we do not get SMBWrite returning EBADF + if writepages is racing with close. Note that writepages + does not specify a file handle, so it is possible for a file + to be opened twice, and the application close the "wrong" + file handle - in these cases we delay long enough to allow + the SMBWrite to get on the wire before the SMB Close. + We allow total wait here over 45 seconds, more than + oplock break time, and more than enough to allow any write + to complete on the server, or to time out on the client */ + while ((atomic_read(&pSMBFile->wrtPending) != 0) + && (timeout <= 50000)) { + cERROR(1, ("writes pending, delay free of handle")); + msleep(timeout); + timeout *= 8; + } kfree(pSMBFile->search_resume_name); kfree(file->private_data); file->private_data = NULL; } else rc = -EBADF; + read_lock(&GlobalSMBSeslock); if (list_empty(&(CIFS_I(inode)->openFileList))) { cFYI(1, ("closing last open instance for inode %p", inode)); /* if the file is not open we do not know if we can cache info @@ -535,6 +553,7 @@ int cifs_close(struct inode *inode, struct file *file) CIFS_I(inode)->clientCanCacheRead = FALSE; CIFS_I(inode)->clientCanCacheAll = FALSE; } + read_unlock(&GlobalSMBSeslock); if ((rc == 0) && CIFS_I(inode)->write_behind_rc) rc = CIFS_I(inode)->write_behind_rc; FreeXid(xid); @@ -767,7 +786,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) mutex_lock(&fid->lock_mutex); list_for_each_entry_safe(li, tmp, &fid->llist, llist) { if (pfLock->fl_start <= li->offset && - length >= li->length) { + (pfLock->fl_start + length) >= + (li->offset + li->length)) { stored_rc = CIFSSMBLock(xid, pTcon, netfid, li->length, li->offset, @@ -1022,6 +1042,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) } read_lock(&GlobalSMBSeslock); +refind_writable: list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { if (open_file->closePend) continue; @@ -1029,24 +1050,49 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { atomic_inc(&open_file->wrtPending); + + if (!open_file->invalidHandle) { + /* found a good writable file */ + read_unlock(&GlobalSMBSeslock); + return open_file; + } + read_unlock(&GlobalSMBSeslock); - if ((open_file->invalidHandle) && - (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) { - rc = cifs_reopen_file(open_file->pfile, FALSE); - /* if it fails, try another handle - might be */ - /* dangerous to hold up writepages with retry */ - if (rc) { - cFYI(1, - ("failed on reopen file in wp")); + /* Had to unlock since following call can block */ + rc = cifs_reopen_file(open_file->pfile, FALSE); + if (!rc) { + if (!open_file->closePend) + return open_file; + else { /* start over in case this was deleted */ + /* since the list could be modified */ read_lock(&GlobalSMBSeslock); - /* can not use this handle, no write - pending on this one after all */ - atomic_dec - (&open_file->wrtPending); - continue; + atomic_dec(&open_file->wrtPending); + goto refind_writable; } } - return open_file; + + /* if it fails, try another handle if possible - + (we can not do this if closePending since + loop could be modified - in which case we + have to start at the beginning of the list + again. Note that it would be bad + to hold up writepages here (rather than + in caller) with continuous retries */ + cFYI(1, ("wp failed on reopen file")); + read_lock(&GlobalSMBSeslock); + /* can not use this handle, no write + pending on this one after all */ + atomic_dec(&open_file->wrtPending); + + if (open_file->closePend) /* list could have changed */ + goto refind_writable; + /* else we simply continue to the next entry. Thus + we do not loop on reopen errors. If we + can not reopen the file, for example if we + reconnected to a server with another client + racing to delete or lock the file we would not + make progress if we restarted before the beginning + of the loop here. */ } } read_unlock(&GlobalSMBSeslock); @@ -1709,7 +1755,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, struct page *page; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; - int bytes_read = 0; + unsigned int bytes_read = 0; unsigned int read_size, i; char *smb_read_data = NULL; struct smb_com_read_rsp *pSMBr; @@ -1803,7 +1849,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, i += bytes_read >> PAGE_CACHE_SHIFT; cifs_stats_bytes_read(pTcon, bytes_read); - if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { + if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) { i++; /* account for partial page */ /* server copy of file can have smaller size diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 279f3c5e0ce3..5e8b388be3b6 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -115,7 +115,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode->i_mode = le64_to_cpu(findData.Permissions); /* since we set the inode type below we need to mask off to avoid strange results if bits set above */ - inode->i_mode &= ~S_IFMT; + inode->i_mode &= ~S_IFMT; if (type == UNIX_FILE) { inode->i_mode |= S_IFREG; } else if (type == UNIX_SYMLINK) { @@ -575,19 +575,33 @@ int cifs_get_inode_info(struct inode **pinode, return rc; } +static const struct inode_operations cifs_ipc_inode_ops = { + .lookup = cifs_lookup, +}; + /* gets root inode */ void cifs_read_inode(struct inode *inode) { - int xid; + int xid, rc; struct cifs_sb_info *cifs_sb; cifs_sb = CIFS_SB(inode->i_sb); xid = GetXid(); if (cifs_sb->tcon->unix_ext) - cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); + rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); else - cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); + rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); + if (rc && cifs_sb->tcon->ipc) { + cFYI(1, ("ipc connection - fake read inode")); + inode->i_mode |= S_IFDIR; + inode->i_nlink = 2; + inode->i_op = &cifs_ipc_inode_ops; + inode->i_fop = &simple_dir_operations; + inode->i_uid = cifs_sb->mnt_uid; + inode->i_gid = cifs_sb->mnt_gid; + } + /* can not call macro FreeXid here since in a void func */ _FreeXid(xid); } @@ -919,18 +933,25 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) goto mkdir_out; } + mode &= ~current->fs->umask; rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, NULL /* netfid */, pInfo, &oplock, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - if (rc) { + if (rc == -EOPNOTSUPP) { + kfree(pInfo); + goto mkdir_retry_old; + } else if (rc) { cFYI(1, ("posix mkdir returned 0x%x", rc)); d_drop(direntry); } else { int obj_type; - if (pInfo->Type == -1) /* no return info - go query */ + if (pInfo->Type == cpu_to_le32(-1)) { + /* no return info, go query for it */ + kfree(pInfo); goto mkdir_get_info; + } /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */ inc_nlink(inode); @@ -940,8 +961,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) direntry->d_op = &cifs_dentry_ops; newinode = new_inode(inode->i_sb); - if (newinode == NULL) + if (newinode == NULL) { + kfree(pInfo); goto mkdir_get_info; + } /* Is an i_ino of zero legal? */ /* Are there sanity checks we can use to ensure that the server is really filling in that field? */ @@ -972,7 +995,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) kfree(pInfo); goto mkdir_out; } - +mkdir_retry_old: /* BB add setting the equivalent of mode via CreateX w/ACLs */ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -1377,8 +1400,17 @@ static int cifs_vmtruncate(struct inode *inode, loff_t offset) } i_size_write(inode, offset); spin_unlock(&inode->i_lock); + /* + * unmap_mapping_range is called twice, first simply for efficiency + * so that truncate_inode_pages does fewer single-page unmaps. However + * after this first call, and before truncate_inode_pages finishes, + * it is possible for private pages to be COWed, which remain after + * truncate_inode_pages finishes, hence the second unmap_mapping_range + * call must be made for correctness. + */ unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); truncate_inode_pages(mapping, offset); + unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); goto out_truncate; do_expand: @@ -1469,7 +1501,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) atomic_dec(&open_file->wrtPending); cFYI(1, ("SetFSize for attrs rc = %d", rc)); if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { - int bytes_written; + unsigned int bytes_written; rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size, &bytes_written, NULL, NULL, @@ -1502,7 +1534,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc == 0) { - int bytes_written; + unsigned int bytes_written; rc = CIFSSMBWrite(xid, pTcon, netfid, 0, attrs->ia_size, diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 6a85ef7b8797..11f265726db7 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -237,7 +237,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) char *tmp_path = NULL; char *tmpbuffer; unsigned char *referrals = NULL; - int num_referrals = 0; + unsigned int num_referrals = 0; int len; __u16 fid; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 0bcec0844bee..51ec681fe74a 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -169,7 +169,6 @@ cifs_buf_get(void) void cifs_buf_release(void *buf_to_free) { - if (buf_to_free == NULL) { /* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/ return; diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 2bfed3f45d0f..f06359cb22ee 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -114,10 +114,16 @@ static const struct smb_to_posix_error mapping_table_ERRSRV[] = { {ERRusempx, -EIO}, {ERRusestd, -EIO}, {ERR_NOTIFY_ENUM_DIR, -ENOBUFS}, - {ERRaccountexpired, -EACCES}, + {ERRnoSuchUser, -EACCES}, +/* {ERRaccountexpired, -EACCES}, {ERRbadclient, -EACCES}, {ERRbadLogonTime, -EACCES}, - {ERRpasswordExpired, -EACCES}, + {ERRpasswordExpired, -EACCES},*/ + {ERRaccountexpired, -EKEYEXPIRED}, + {ERRbadclient, -EACCES}, + {ERRbadLogonTime, -EACCES}, + {ERRpasswordExpired, -EKEYEXPIRED}, + {ERRnosupport, -EINVAL}, {0, 0} }; @@ -270,7 +276,7 @@ static const struct { from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE during the session setup } */ { - ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { + ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { /* could map to 2238 */ ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, { ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, { ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, { @@ -285,10 +291,10 @@ static const struct { ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, { ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, { ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { - ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { - ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { + ERRSRV, ERRbadLogonTime, NT_STATUS_INVALID_LOGON_HOURS}, { + ERRSRV, ERRbadclient, NT_STATUS_INVALID_WORKSTATION}, { ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, { - ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { + ERRSRV, ERRaccountexpired, NT_STATUS_ACCOUNT_DISABLED}, { ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, { @@ -585,7 +591,7 @@ static const struct { ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, { ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, { ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, { - ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, { + ERRSRV, ERRaccountexpired, NT_STATUS_ACCOUNT_EXPIRED}, { ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, { ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, { ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, { @@ -754,7 +760,7 @@ ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode) } int -map_smb_to_linux_error(struct smb_hdr *smb) +map_smb_to_linux_error(struct smb_hdr *smb, int logErr) { unsigned int i; int rc = -EIO; /* if transport error smb error may not be set */ @@ -771,7 +777,9 @@ map_smb_to_linux_error(struct smb_hdr *smb) /* translate the newer STATUS codes to old style SMB errors * and then to POSIX errors */ __u32 err = le32_to_cpu(smb->Status.CifsError); - if (cifsFYI & CIFS_RC) + if (logErr && (err != (NT_STATUS_MORE_PROCESSING_REQUIRED))) + cifs_print_status(err); + else if (cifsFYI & CIFS_RC) cifs_print_status(err); ntstatus_to_dos(err, &smberrclass, &smberrcode); } else { @@ -813,7 +821,7 @@ map_smb_to_linux_error(struct smb_hdr *smb) } /* else ERRHRD class errors or junk - return EIO */ - cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", + cFYI(1, ("Mapping smb error code %d to POSIX err %d", smberrcode, rc)); /* generic corrective action e.g. reconnect SMB session on @@ -899,8 +907,11 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) cERROR(1, ("illegal hours %d", st->Hours)); days = sd->Day; month = sd->Month; - if ((days > 31) || (month > 12)) + if ((days > 31) || (month > 12)) { cERROR(1, ("illegal date, month %d day: %d", month, days)); + if (month > 12) + month = 12; + } month -= 1; days += total_days_of_prev_months[month]; days += 3652; /* account for difference in days between 1980 and 1970 */ diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 916df9431336..3746580e9701 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -121,7 +121,7 @@ static void AdjustForTZ(struct cifsTconInfo *tcon, struct inode *inode) static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, - char *buf, int *pobject_type, int isNewInode) + char *buf, unsigned int *pobject_type, int isNewInode) { loff_t local_size; struct timespec local_mtime; @@ -294,7 +294,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, } static void unix_fill_in_inode(struct inode *tmp_inode, - FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode) + FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode) { loff_t local_size; struct timespec local_mtime; @@ -826,7 +826,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file, int rc = 0; struct qstr qstring; struct cifsFileInfo *pCifsF; - unsigned obj_type; + unsigned int obj_type; ino_t inum; struct cifs_sb_info *cifs_sb; struct inode *tmp_inode; @@ -1067,7 +1067,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) for (i = 0; (i < num_to_fill) && (rc == 0); i++) { if (current_entry == NULL) { /* evaluate whether this case is an error */ - cERROR(1,("past end of SMB num to fill %d i %d", + cERROR(1, ("past SMB end, num to fill %d i %d", num_to_fill, i)); break; } diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 892be9b4d1f3..899dc6078d9a 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -67,14 +67,59 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) pSMB->req.hdr.Flags2 |= SMBFLG2_DFS; capabilities |= CAP_DFS; } - if (ses->capabilities & CAP_UNIX) { + if (ses->capabilities & CAP_UNIX) capabilities |= CAP_UNIX; - } /* BB check whether to init vcnum BB */ return capabilities; } +static void +unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) +{ + char *bcc_ptr = *pbcc_area; + int bytes_ret = 0; + + /* Copy OS version */ + bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, + nls_cp); + bcc_ptr += 2 * bytes_ret; + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release, + 32, nls_cp); + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* trailing null */ + + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, + 32, nls_cp); + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* trailing null */ + + *pbcc_area = bcc_ptr; +} + +static void unicode_domain_string(char **pbcc_area, struct cifsSesInfo *ses, + const struct nls_table *nls_cp) +{ + char *bcc_ptr = *pbcc_area; + int bytes_ret = 0; + + /* copy domain */ + if (ses->domainName == NULL) { + /* Sending null domain better than using a bogus domain name (as + we did briefly in 2.6.18) since server will use its default */ + *bcc_ptr = 0; + *(bcc_ptr+1) = 0; + bytes_ret = 0; + } else + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, + 256, nls_cp); + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* account for null terminator */ + + *pbcc_area = bcc_ptr; +} + + static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, const struct nls_table *nls_cp) { @@ -100,32 +145,9 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, } bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null termination */ - /* copy domain */ - if (ses->domainName == NULL) { - /* Sending null domain better than using a bogus domain name (as - we did briefly in 2.6.18) since server will use its default */ - *bcc_ptr = 0; - *(bcc_ptr+1) = 0; - bytes_ret = 0; - } else - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, - 256, nls_cp); - bcc_ptr += 2 * bytes_ret; - bcc_ptr += 2; /* account for null terminator */ - - /* Copy OS version */ - bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, - nls_cp); - bcc_ptr += 2 * bytes_ret; - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release, - 32, nls_cp); - bcc_ptr += 2 * bytes_ret; - bcc_ptr += 2; /* trailing null */ - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, - 32, nls_cp); - bcc_ptr += 2 * bytes_ret; - bcc_ptr += 2; /* trailing null */ + unicode_domain_string(&bcc_ptr, ses, nls_cp); + unicode_oslm_strings(&bcc_ptr, nls_cp); *pbcc_area = bcc_ptr; } @@ -203,14 +225,11 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, if (len >= words_left) return rc; - if (ses->serverOS) - kfree(ses->serverOS); + kfree(ses->serverOS); /* UTF-8 string will not grow more than four times as big as UCS-16 */ ses->serverOS = kzalloc(4 * len, GFP_KERNEL); - if (ses->serverOS != NULL) { - cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, - nls_cp); - } + if (ses->serverOS != NULL) + cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); data += 2 * (len + 1); words_left -= len + 1; @@ -220,8 +239,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, if (len >= words_left) return rc; - if (ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */ if (ses->serverNOS != NULL) { cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, @@ -240,8 +258,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, if (len > words_left) return rc; - if (ses->serverDomain) - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ if (ses->serverDomain != NULL) { cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, @@ -271,8 +288,7 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, if (len >= bleft) return rc; - if (ses->serverOS) - kfree(ses->serverOS); + kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1, GFP_KERNEL); if (ses->serverOS) @@ -289,8 +305,7 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, if (len >= bleft) return rc; - if (ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); if (ses->serverNOS) @@ -479,7 +494,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, if (ses->capabilities & CAP_UNICODE) { if (iov[0].iov_len % 2) { *bcc_ptr = 0; - } bcc_ptr++; + bcc_ptr++; + } unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); } else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); @@ -497,7 +513,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, iov[1].iov_base = str_area; iov[1].iov_len = count; - rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0); + rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, + 0 /* not long op */, 1 /* log NT STATUS if any */ ); /* SMB request buf freed in SendReceive2 */ cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index 2ef0be288820..7f50e8577c1c 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h @@ -173,9 +173,10 @@ #define ERRusestd 251 /* temporarily unable to use either raw or mpx */ #define ERR_NOTIFY_ENUM_DIR 1024 +#define ERRnoSuchUser 2238 /* user account does not exist */ #define ERRaccountexpired 2239 -#define ERRbadclient 2240 -#define ERRbadLogonTime 2241 +#define ERRbadclient 2240 /* can not logon from this client */ +#define ERRbadLogonTime 2241 /* logon hours do not allow this */ #define ERRpasswordExpired 2242 #define ERRnetlogonNotStarted 2455 #define ERRnosupport 0xFFFF diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 746bc9405db1..7ed32b3cb781 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -55,7 +55,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) if (temp == NULL) return temp; else { - memset(temp, 0, sizeof (struct mid_q_entry)); + memset(temp, 0, sizeof(struct mid_q_entry)); temp->mid = smb_buffer->Mid; /* always LE */ temp->pid = current->pid; temp->command = smb_buffer->Command; @@ -158,7 +158,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, iov.iov_len = len; smb_msg.msg_name = sin; - smb_msg.msg_namelen = sizeof (struct sockaddr); + smb_msg.msg_namelen = sizeof(struct sockaddr); smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ @@ -228,7 +228,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, return -ENOTSOCK; /* BB eventually add reconnect code here */ smb_msg.msg_name = sin; - smb_msg.msg_namelen = sizeof (struct sockaddr); + smb_msg.msg_namelen = sizeof(struct sockaddr); smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ @@ -363,9 +363,8 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, } /* else ok - we are setting up session */ } *ppmidQ = AllocMidQEntry(in_buf, ses); - if (*ppmidQ == NULL) { + if (*ppmidQ == NULL) return -ENOMEM; - } return 0; } @@ -419,7 +418,7 @@ static int wait_for_response(struct cifsSesInfo *ses, int SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, struct kvec *iov, int n_vec, int *pRespBufType /* ret */, - const int long_op) + const int long_op, const int logError) { int rc = 0; unsigned int receive_len; @@ -465,7 +464,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, wake_up(&ses->server->request_q); return rc; } - rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; @@ -568,13 +566,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, } /* BB special case reconnect tid and uid here? */ - /* BB special case Errbadpassword and pwdexpired here */ - rc = map_smb_to_linux_error(midQ->resp_buf); + rc = map_smb_to_linux_error(midQ->resp_buf, logError); /* convert ByteCount if necessary */ - if (receive_len >= - sizeof (struct smb_hdr) - - 4 /* do not count RFC1001 header */ + + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) BCC(midQ->resp_buf) = le16_to_cpu(BCC_LE(midQ->resp_buf)); @@ -749,12 +745,11 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, *pbytes_returned = out_buf->smb_buf_length; /* BB special case reconnect tid and uid here? */ - rc = map_smb_to_linux_error(out_buf); + rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); /* convert ByteCount if necessary */ - if (receive_len >= - sizeof (struct smb_hdr) - - 4 /* do not count RFC1001 header */ + + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); } else { @@ -993,12 +988,11 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, *pbytes_returned = out_buf->smb_buf_length; /* BB special case reconnect tid and uid here? */ - rc = map_smb_to_linux_error(out_buf); + rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); /* convert ByteCount if necessary */ - if (receive_len >= - sizeof (struct smb_hdr) - - 4 /* do not count RFC1001 header */ + + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); } else { diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index f61e433d281c..369e838bebd3 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -261,21 +261,26 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); -/* else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { +#ifdef CONFIG_CIFS_EXPERIMENTAL + else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { __u16 fid; int oplock = FALSE; - rc = CIFSSMBOpen(xid, pTcon, full_path, - FILE_OPEN, GENERIC_READ, 0, &fid, - &oplock, NULL, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + if (experimEnabled) + rc = CIFSSMBOpen(xid, pTcon, full_path, + FILE_OPEN, GENERIC_READ, 0, &fid, + &oplock, NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + /* else rc is EOPNOTSUPP from above */ + if(rc == 0) { rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, ea_value, buf_size, ACL_TYPE_ACCESS); CIFSSMBClose(xid, pTcon, fid); } - } */ /* BB enable after fixing up return data */ + } +#endif /* EXPERIMENTAL */ #else cFYI(1, ("query POSIX ACL not supported yet")); #endif /* CONFIG_CIFS_POSIX */ diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index cdb4c07a7870..359e531094dd 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -51,7 +51,7 @@ static void *alloc_upcall(int opcode, int size) inp->ih.opcode = opcode; inp->ih.pid = current->pid; - inp->ih.pgid = process_group(current); + inp->ih.pgid = task_pgrp_nr(current); #ifdef CONFIG_CODA_FS_OLD_API memset(&inp->ih.cred, 0, sizeof(struct coda_cred)); inp->ih.cred.cr_fsuid = current->fsuid; diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 6438941ab1f8..4f741546f4bb 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -456,7 +456,7 @@ static int check_version(struct dlm_write_request *req) printk(KERN_DEBUG "dlm: process %s (%d) version mismatch " "user (%d.%d.%d) kernel (%d.%d.%d)\n", current->comm, - current->pid, + task_pid_nr(current), req->version[0], req->version[1], req->version[2], diff --git a/fs/eventpoll.c b/fs/eventpoll.c index de6189291954..34f68f3a069a 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -325,15 +325,14 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq) int wake_nests = 0; unsigned long flags; struct task_struct *this_task = current; - struct list_head *lsthead = &psw->wake_task_list, *lnk; + struct list_head *lsthead = &psw->wake_task_list; struct wake_task_node *tncur; struct wake_task_node tnode; spin_lock_irqsave(&psw->lock, flags); /* Try to see if the current task is already inside this wakeup call */ - list_for_each(lnk, lsthead) { - tncur = list_entry(lnk, struct wake_task_node, llink); + list_for_each_entry(tncur, lsthead, llink) { if (tncur->wq == wq || (tncur->task == this_task && ++wake_nests > EP_MAX_POLLWAKE_NESTS)) { diff --git a/fs/exec.c b/fs/exec.c index 070ddf13cb71..2c942e2d14ea 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -234,7 +234,7 @@ static int __bprm_mm_init(struct linux_binprm *bprm) vma->vm_start = vma->vm_end - PAGE_SIZE; vma->vm_flags = VM_STACK_FLAGS; - vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); err = insert_vm_struct(mm, vma); if (err) { up_write(&mm->mmap_sem); @@ -775,8 +775,8 @@ static int de_thread(struct task_struct *tsk) * Reparenting needs write_lock on tasklist_lock, * so it is safe to do it under read_lock. */ - if (unlikely(tsk->group_leader == child_reaper(tsk))) - tsk->nsproxy->pid_ns->child_reaper = tsk; + if (unlikely(tsk->group_leader == task_child_reaper(tsk))) + task_active_pid_ns(tsk)->child_reaper = tsk; zap_other_threads(tsk); read_unlock(&tasklist_lock); @@ -841,8 +841,8 @@ static int de_thread(struct task_struct *tsk) */ tsk->start_time = leader->start_time; - BUG_ON(leader->tgid != tsk->tgid); - BUG_ON(tsk->pid == tsk->tgid); + BUG_ON(!same_thread_group(leader, tsk)); + BUG_ON(has_group_leader_pid(tsk)); /* * An exec() starts a new thread group with the * TGID of the previous thread group. Rehash the @@ -857,7 +857,7 @@ static int de_thread(struct task_struct *tsk) */ detach_pid(tsk, PIDTYPE_PID); tsk->pid = leader->pid; - attach_pid(tsk, PIDTYPE_PID, find_pid(tsk->pid)); + attach_pid(tsk, PIDTYPE_PID, task_pid(leader)); transfer_pid(leader, tsk, PIDTYPE_PGID); transfer_pid(leader, tsk, PIDTYPE_SID); list_replace_rcu(&leader->tasks, &tsk->tasks); @@ -1433,7 +1433,7 @@ static int format_corename(char *corename, const char *pattern, long signr) case 'p': pid_in_pattern = 1; rc = snprintf(out_ptr, out_end - out_ptr, - "%d", current->tgid); + "%d", task_tgid_vnr(current)); if (rc > out_end - out_ptr) goto out; out_ptr += rc; @@ -1513,7 +1513,7 @@ static int format_corename(char *corename, const char *pattern, long signr) if (!ispipe && !pid_in_pattern && (core_uses_pid || atomic_read(¤t->mm->mm_users) != 1)) { rc = snprintf(out_ptr, out_end - out_ptr, - ".%d", current->tgid); + ".%d", task_tgid_vnr(current)); if (rc > out_end - out_ptr) goto out; out_ptr += rc; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 3dec003b773e..9b162cd6c16c 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -2954,7 +2954,7 @@ int ext3_write_inode(struct inode *inode, int wait) return 0; if (ext3_journal_current_handle()) { - jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n"); + jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n"); dump_stack(); return -EIO; } diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index f58cbb26323e..408373819e34 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -741,12 +741,11 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, } } else { /* Allocate a buffer where we construct the new block. */ - s->base = kmalloc(sb->s_blocksize, GFP_KERNEL); + s->base = kzalloc(sb->s_blocksize, GFP_KERNEL); /* assert(header == s->base) */ error = -ENOMEM; if (s->base == NULL) goto cleanup; - memset(s->base, 0, sb->s_blocksize); header(s->base)->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); header(s->base)->h_blocks = cpu_to_le32(1); header(s->base)->h_refcount = cpu_to_le32(1); diff --git a/fs/fcntl.c b/fs/fcntl.c index c9db73fc5e3d..8685263ccc4a 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -18,6 +18,7 @@ #include <linux/ptrace.h> #include <linux/signal.h> #include <linux/rcupdate.h> +#include <linux/pid_namespace.h> #include <asm/poll.h> #include <asm/siginfo.h> @@ -292,7 +293,7 @@ int f_setown(struct file *filp, unsigned long arg, int force) who = -who; } rcu_read_lock(); - pid = find_pid(who); + pid = find_vpid(who); result = __f_setown(filp, pid, type, force); rcu_read_unlock(); return result; @@ -308,7 +309,7 @@ pid_t f_getown(struct file *filp) { pid_t pid; read_lock(&filp->f_owner.lock); - pid = pid_nr(filp->f_owner.pid); + pid = pid_nr_ns(filp->f_owner.pid, current->nsproxy->pid_ns); if (filp->f_owner.pid_type == PIDTYPE_PGID) pid = -pid; read_unlock(&filp->f_owner.lock); diff --git a/fs/file_table.c b/fs/file_table.c index 3176fefc92e1..664e3f2309b8 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -323,12 +323,11 @@ void file_kill(struct file *file) int fs_may_remount_ro(struct super_block *sb) { - struct list_head *p; + struct file *file; /* Check that no files are currently opened for writing. */ file_list_lock(); - list_for_each(p, &sb->s_files) { - struct file *file = list_entry(p, struct file, f_u.fu_list); + list_for_each_entry(file, &sb->s_files, f_u.fu_list) { struct inode *inode = file->f_path.dentry->d_inode; /* File with pending delete? */ diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 686734ff973d..0fca82021d76 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -89,7 +89,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) printk(KERN_DEBUG "%s(%d): dirtied inode %lu (%s) on %s\n", - current->comm, current->pid, inode->i_ino, + current->comm, task_pid_nr(current), inode->i_ino, name, inode->i_sb->s_id); } diff --git a/fs/ioprio.c b/fs/ioprio.c index 10d2c211d18b..d6ff77e8e7ec 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -25,6 +25,7 @@ #include <linux/capability.h> #include <linux/syscalls.h> #include <linux/security.h> +#include <linux/pid_namespace.h> static int set_task_ioprio(struct task_struct *task, int ioprio) { @@ -93,7 +94,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio) if (!who) p = current; else - p = find_task_by_pid(who); + p = find_task_by_vpid(who); if (p) ret = set_task_ioprio(p, ioprio); break; @@ -101,7 +102,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio) if (!who) pgrp = task_pgrp(current); else - pgrp = find_pid(who); + pgrp = find_vpid(who); do_each_pid_task(pgrp, PIDTYPE_PGID, p) { ret = set_task_ioprio(p, ioprio); if (ret) @@ -180,7 +181,7 @@ asmlinkage long sys_ioprio_get(int which, int who) if (!who) p = current; else - p = find_task_by_pid(who); + p = find_task_by_vpid(who); if (p) ret = get_task_ioprio(p); break; @@ -188,7 +189,7 @@ asmlinkage long sys_ioprio_get(int which, int who) if (!who) pgrp = task_pgrp(current); else - pgrp = find_pid(who); + pgrp = find_vpid(who); do_each_pid_task(pgrp, PIDTYPE_PGID, p) { tmpio = get_task_ioprio(p); if (tmpio < 0) diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index a263d82761df..8f1f2aa5fb39 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -466,7 +466,7 @@ void journal_commit_transaction(journal_t *journal) spin_unlock(&journal->j_list_lock); if (err) - __journal_abort_hard(journal); + journal_abort(journal, err); journal_write_revoke_records(journal, commit_transaction); @@ -524,7 +524,7 @@ void journal_commit_transaction(journal_t *journal) descriptor = journal_get_descriptor_buffer(journal); if (!descriptor) { - __journal_abort_hard(journal); + journal_abort(journal, -EIO); continue; } @@ -557,7 +557,7 @@ void journal_commit_transaction(journal_t *journal) and repeat this loop: we'll fall into the refile-on-abort condition above. */ if (err) { - __journal_abort_hard(journal); + journal_abort(journal, err); continue; } @@ -748,7 +748,7 @@ wait_for_iobuf: err = -EIO; if (err) - __journal_abort_hard(journal); + journal_abort(journal, err); /* End of a transaction! Finally, we can do checkpoint processing: any buffers committed as a result of this diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 5d9fec0b7ebd..5d14243499d4 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -35,6 +35,7 @@ #include <linux/kthread.h> #include <linux/poison.h> #include <linux/proc_fs.h> +#include <linux/debugfs.h> #include <asm/uaccess.h> #include <asm/page.h> @@ -654,10 +655,9 @@ static journal_t * journal_init_common (void) journal_t *journal; int err; - journal = kmalloc(sizeof(*journal), GFP_KERNEL); + journal = kzalloc(sizeof(*journal), GFP_KERNEL); if (!journal) goto fail; - memset(journal, 0, sizeof(*journal)); init_waitqueue_head(&journal->j_wait_transaction_locked); init_waitqueue_head(&journal->j_wait_logspace); @@ -1852,64 +1852,41 @@ void journal_put_journal_head(struct journal_head *jh) } /* - * /proc tunables + * debugfs tunables */ -#if defined(CONFIG_JBD_DEBUG) -int journal_enable_debug; -EXPORT_SYMBOL(journal_enable_debug); -#endif +#ifdef CONFIG_JBD_DEBUG -#if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS) +u8 journal_enable_debug __read_mostly; +EXPORT_SYMBOL(journal_enable_debug); -static struct proc_dir_entry *proc_jbd_debug; +static struct dentry *jbd_debugfs_dir; +static struct dentry *jbd_debug; -static int read_jbd_debug(char *page, char **start, off_t off, - int count, int *eof, void *data) +static void __init jbd_create_debugfs_entry(void) { - int ret; - - ret = sprintf(page + off, "%d\n", journal_enable_debug); - *eof = 1; - return ret; + jbd_debugfs_dir = debugfs_create_dir("jbd", NULL); + if (jbd_debugfs_dir) + jbd_debug = debugfs_create_u8("jbd-debug", S_IRUGO, + jbd_debugfs_dir, + &journal_enable_debug); } -static int write_jbd_debug(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static void __exit jbd_remove_debugfs_entry(void) { - char buf[32]; - - if (count > ARRAY_SIZE(buf) - 1) - count = ARRAY_SIZE(buf) - 1; - if (copy_from_user(buf, buffer, count)) - return -EFAULT; - buf[ARRAY_SIZE(buf) - 1] = '\0'; - journal_enable_debug = simple_strtoul(buf, NULL, 10); - return count; + debugfs_remove(jbd_debug); + debugfs_remove(jbd_debugfs_dir); } -#define JBD_PROC_NAME "sys/fs/jbd-debug" +#else -static void __init create_jbd_proc_entry(void) +static inline void jbd_create_debugfs_entry(void) { - proc_jbd_debug = create_proc_entry(JBD_PROC_NAME, 0644, NULL); - if (proc_jbd_debug) { - /* Why is this so hard? */ - proc_jbd_debug->read_proc = read_jbd_debug; - proc_jbd_debug->write_proc = write_jbd_debug; - } } -static void __exit remove_jbd_proc_entry(void) +static inline void jbd_remove_debugfs_entry(void) { - if (proc_jbd_debug) - remove_proc_entry(JBD_PROC_NAME, NULL); } -#else - -#define create_jbd_proc_entry() do {} while (0) -#define remove_jbd_proc_entry() do {} while (0) - #endif struct kmem_cache *jbd_handle_cache; @@ -1966,7 +1943,7 @@ static int __init journal_init(void) ret = journal_init_caches(); if (ret != 0) journal_destroy_caches(); - create_jbd_proc_entry(); + jbd_create_debugfs_entry(); return ret; } @@ -1977,7 +1954,7 @@ static void __exit journal_exit(void) if (n) printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n); #endif - remove_jbd_proc_entry(); + jbd_remove_debugfs_entry(); journal_destroy_caches(); } diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index 2a5f4b833e35..c5d9694b6a2f 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -250,10 +250,10 @@ int journal_recover(journal_t *journal) if (!err) err = do_one_pass(journal, &info, PASS_REPLAY); - jbd_debug(0, "JBD: recovery, exit status %d, " + jbd_debug(1, "JBD: recovery, exit status %d, " "recovered transactions %u to %u\n", err, info.start_transaction, info.end_transaction); - jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n", + jbd_debug(1, "JBD: Replayed %d and revoked %d/%d blocks\n", info.nr_replays, info.nr_revoke_hits, info.nr_revokes); /* Restart the log at the next transaction ID, thus invalidating @@ -297,7 +297,7 @@ int journal_skip_recovery(journal_t *journal) #ifdef CONFIG_JBD_DEBUG int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence); #endif - jbd_debug(0, + jbd_debug(1, "JBD: ignoring %d transaction%s from the journal.\n", dropped, (dropped == 1) ? "" : "s"); journal->j_transaction_sequence = ++info.end_transaction; diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 9841b1e5af03..08ff6c7028cc 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -96,13 +96,12 @@ static int start_this_handle(journal_t *journal, handle_t *handle) alloc_transaction: if (!journal->j_running_transaction) { - new_transaction = kmalloc(sizeof(*new_transaction), + new_transaction = kzalloc(sizeof(*new_transaction), GFP_NOFS|__GFP_NOFAIL); if (!new_transaction) { ret = -ENOMEM; goto out; } - memset(new_transaction, 0, sizeof(*new_transaction)); } jbd_debug(3, "New handle %p going live.\n", handle); diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index 2a49f2c51a9f..4130adabd76e 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h @@ -80,28 +80,28 @@ #define JFFS2_ERROR(fmt, ...) \ do { \ printk(JFFS2_ERR_MSG_PREFIX \ - " (%d) %s: " fmt, current->pid, \ + " (%d) %s: " fmt, task_pid_nr(current), \ __FUNCTION__ , ##__VA_ARGS__); \ } while(0) #define JFFS2_WARNING(fmt, ...) \ do { \ printk(JFFS2_WARN_MSG_PREFIX \ - " (%d) %s: " fmt, current->pid, \ + " (%d) %s: " fmt, task_pid_nr(current), \ __FUNCTION__ , ##__VA_ARGS__); \ } while(0) #define JFFS2_NOTICE(fmt, ...) \ do { \ printk(JFFS2_NOTICE_MSG_PREFIX \ - " (%d) %s: " fmt, current->pid, \ + " (%d) %s: " fmt, task_pid_nr(current), \ __FUNCTION__ , ##__VA_ARGS__); \ } while(0) #define JFFS2_DEBUG(fmt, ...) \ do { \ printk(JFFS2_DBG_MSG_PREFIX \ - " (%d) %s: " fmt, current->pid, \ + " (%d) %s: " fmt, task_pid_nr(current), \ __FUNCTION__ , ##__VA_ARGS__); \ } while(0) diff --git a/fs/namespace.c b/fs/namespace.c index 07daa7972591..860752998fb3 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1411,7 +1411,7 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, mnt_flags |= MNT_RELATIME; flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | - MS_NOATIME | MS_NODIRATIME | MS_RELATIME); + MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT); /* ... and get the mountpoint */ retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 46934c97f8f7..d0199189924c 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1029,13 +1029,13 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (EX_WGATHER(exp)) { if (atomic_read(&inode->i_writecount) > 1 || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) { - dprintk("nfsd: write defer %d\n", current->pid); + dprintk("nfsd: write defer %d\n", task_pid_nr(current)); msleep(10); - dprintk("nfsd: write resume %d\n", current->pid); + dprintk("nfsd: write resume %d\n", task_pid_nr(current)); } if (inode->i_state & I_DIRTY) { - dprintk("nfsd: write sync %d\n", current->pid); + dprintk("nfsd: write sync %d\n", task_pid_nr(current)); host_err=nfsd_sync(file); } #if 0 diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index f14b541fab95..9cc7c0418b70 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -1372,7 +1372,7 @@ static ssize_t o2hb_region_pid_read(struct o2hb_region *reg, spin_lock(&o2hb_live_lock); if (reg->hr_task) - pid = reg->hr_task->pid; + pid = task_pid_nr(reg->hr_task); spin_unlock(&o2hb_live_lock); if (!pid) diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h index 75cd877f6d42..cd046060114e 100644 --- a/fs/ocfs2/cluster/masklog.h +++ b/fs/ocfs2/cluster/masklog.h @@ -192,7 +192,7 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits; * previous token if args expands to nothing. */ #define __mlog_printk(level, fmt, args...) \ - printk(level "(%u,%lu):%s:%d " fmt, current->pid, \ + printk(level "(%u,%lu):%s:%d " fmt, task_pid_nr(current), \ __mlog_cpu_guess, __PRETTY_FUNCTION__, __LINE__ , \ ##args) diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index a2c33160bfd6..2fde7bf91434 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -259,7 +259,7 @@ static void dlm_print_reco_node_status(struct dlm_ctxt *dlm) struct dlm_lock_resource *res; mlog(ML_NOTICE, "%s(%d): recovery info, state=%s, dead=%u, master=%u\n", - dlm->name, dlm->dlm_reco_thread_task->pid, + dlm->name, task_pid_nr(dlm->dlm_reco_thread_task), dlm->reco.state & DLM_RECO_STATE_ACTIVE ? "ACTIVE" : "inactive", dlm->reco.dead_node, dlm->reco.new_master); @@ -420,7 +420,7 @@ void dlm_wait_for_recovery(struct dlm_ctxt *dlm) if (dlm_in_recovery(dlm)) { mlog(0, "%s: reco thread %d in recovery: " "state=%d, master=%u, dead=%u\n", - dlm->name, dlm->dlm_reco_thread_task->pid, + dlm->name, task_pid_nr(dlm->dlm_reco_thread_task), dlm->reco.state, dlm->reco.new_master, dlm->reco.dead_node); } @@ -483,7 +483,7 @@ static int dlm_do_recovery(struct dlm_ctxt *dlm) return 0; } mlog(0, "%s(%d):recovery thread found node %u in the recovery map!\n", - dlm->name, dlm->dlm_reco_thread_task->pid, + dlm->name, task_pid_nr(dlm->dlm_reco_thread_task), dlm->reco.dead_node); spin_unlock(&dlm->spinlock); @@ -507,7 +507,7 @@ static int dlm_do_recovery(struct dlm_ctxt *dlm) mlog(0, "another node will master this recovery session.\n"); } mlog(0, "dlm=%s (%d), new_master=%u, this node=%u, dead_node=%u\n", - dlm->name, dlm->dlm_reco_thread_task->pid, dlm->reco.new_master, + dlm->name, task_pid_nr(dlm->dlm_reco_thread_task), dlm->reco.new_master, dlm->node_num, dlm->reco.dead_node); /* it is safe to start everything back up here @@ -520,7 +520,7 @@ static int dlm_do_recovery(struct dlm_ctxt *dlm) master_here: mlog(0, "(%d) mastering recovery of %s:%u here(this=%u)!\n", - dlm->dlm_reco_thread_task->pid, + task_pid_nr(dlm->dlm_reco_thread_task), dlm->name, dlm->reco.dead_node, dlm->node_num); status = dlm_remaster_locks(dlm, dlm->reco.dead_node); diff --git a/fs/proc/array.c b/fs/proc/array.c index 27b59f5f3bd1..63c95afb561f 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -77,6 +77,7 @@ #include <linux/cpuset.h> #include <linux/rcupdate.h> #include <linux/delayacct.h> +#include <linux/pid_namespace.h> #include <asm/pgtable.h> #include <asm/processor.h> @@ -145,8 +146,7 @@ static inline const char *get_task_state(struct task_struct *tsk) TASK_UNINTERRUPTIBLE | TASK_STOPPED | TASK_TRACED)) | - (tsk->exit_state & (EXIT_ZOMBIE | - EXIT_DEAD)); + tsk->exit_state; const char **p = &task_state_array[0]; while (state) { @@ -161,8 +161,15 @@ static inline char *task_state(struct task_struct *p, char *buffer) struct group_info *group_info; int g; struct fdtable *fdt = NULL; + struct pid_namespace *ns; + pid_t ppid, tpid; + ns = current->nsproxy->pid_ns; rcu_read_lock(); + ppid = pid_alive(p) ? + task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; + tpid = pid_alive(p) && p->ptrace ? + task_ppid_nr_ns(rcu_dereference(p->parent), ns) : 0; buffer += sprintf(buffer, "State:\t%s\n" "Tgid:\t%d\n" @@ -172,9 +179,9 @@ static inline char *task_state(struct task_struct *p, char *buffer) "Uid:\t%d\t%d\t%d\t%d\n" "Gid:\t%d\t%d\t%d\t%d\n", get_task_state(p), - p->tgid, p->pid, - pid_alive(p) ? rcu_dereference(p->real_parent)->tgid : 0, - pid_alive(p) && p->ptrace ? rcu_dereference(p->parent)->pid : 0, + task_tgid_nr_ns(p, ns), + task_pid_nr_ns(p, ns), + ppid, tpid, p->uid, p->euid, p->suid, p->fsuid, p->gid, p->egid, p->sgid, p->fsgid); @@ -394,6 +401,9 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) unsigned long rsslim = 0; char tcomm[sizeof(task->comm)]; unsigned long flags; + struct pid_namespace *ns; + + ns = current->nsproxy->pid_ns; state = *get_task_state(task); vsize = eip = esp = 0; @@ -416,7 +426,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) struct signal_struct *sig = task->signal; if (sig->tty) { - tty_pgrp = pid_nr(sig->tty->pgrp); + tty_pgrp = pid_nr_ns(sig->tty->pgrp, ns); tty_nr = new_encode_dev(tty_devnum(sig->tty)); } @@ -446,12 +456,12 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) maj_flt += sig->maj_flt; utime = cputime_add(utime, sig->utime); stime = cputime_add(stime, sig->stime); - gtime += cputime_add(gtime, sig->gtime); + gtime = cputime_add(gtime, sig->gtime); } - sid = signal_session(sig); - pgid = process_group(task); - ppid = rcu_dereference(task->real_parent)->tgid; + sid = task_session_nr_ns(task, ns); + pgid = task_pgrp_nr_ns(task, ns); + ppid = task_ppid_nr_ns(task, ns); unlock_task_sighand(task, &flags); } @@ -483,7 +493,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) res = sprintf(buffer, "%d (%s) %c %d %d %d %d %d %u %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n", - task->pid, + task_pid_nr_ns(task, ns), tcomm, state, ppid, diff --git a/fs/proc/base.c b/fs/proc/base.c index 4fe74d156416..39a3d7c969c5 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -63,16 +63,19 @@ #include <linux/mm.h> #include <linux/rcupdate.h> #include <linux/kallsyms.h> +#include <linux/resource.h> #include <linux/module.h> #include <linux/mount.h> #include <linux/security.h> #include <linux/ptrace.h> +#include <linux/cgroup.h> #include <linux/cpuset.h> #include <linux/audit.h> #include <linux/poll.h> #include <linux/nsproxy.h> #include <linux/oom.h> #include <linux/elf.h> +#include <linux/pid_namespace.h> #include "internal.h" /* NOTE: @@ -301,6 +304,78 @@ static int proc_oom_score(struct task_struct *task, char *buffer) return sprintf(buffer, "%lu\n", points); } +struct limit_names { + char *name; + char *unit; +}; + +static const struct limit_names lnames[RLIM_NLIMITS] = { + [RLIMIT_CPU] = {"Max cpu time", "ms"}, + [RLIMIT_FSIZE] = {"Max file size", "bytes"}, + [RLIMIT_DATA] = {"Max data size", "bytes"}, + [RLIMIT_STACK] = {"Max stack size", "bytes"}, + [RLIMIT_CORE] = {"Max core file size", "bytes"}, + [RLIMIT_RSS] = {"Max resident set", "bytes"}, + [RLIMIT_NPROC] = {"Max processes", "processes"}, + [RLIMIT_NOFILE] = {"Max open files", "files"}, + [RLIMIT_MEMLOCK] = {"Max locked memory", "bytes"}, + [RLIMIT_AS] = {"Max address space", "bytes"}, + [RLIMIT_LOCKS] = {"Max file locks", "locks"}, + [RLIMIT_SIGPENDING] = {"Max pending signals", "signals"}, + [RLIMIT_MSGQUEUE] = {"Max msgqueue size", "bytes"}, + [RLIMIT_NICE] = {"Max nice priority", NULL}, + [RLIMIT_RTPRIO] = {"Max realtime priority", NULL}, +}; + +/* Display limits for a process */ +static int proc_pid_limits(struct task_struct *task, char *buffer) +{ + unsigned int i; + int count = 0; + unsigned long flags; + char *bufptr = buffer; + + struct rlimit rlim[RLIM_NLIMITS]; + + rcu_read_lock(); + if (!lock_task_sighand(task,&flags)) { + rcu_read_unlock(); + return 0; + } + memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS); + unlock_task_sighand(task, &flags); + rcu_read_unlock(); + + /* + * print the file header + */ + count += sprintf(&bufptr[count], "%-25s %-20s %-20s %-10s\n", + "Limit", "Soft Limit", "Hard Limit", "Units"); + + for (i = 0; i < RLIM_NLIMITS; i++) { + if (rlim[i].rlim_cur == RLIM_INFINITY) + count += sprintf(&bufptr[count], "%-25s %-20s ", + lnames[i].name, "unlimited"); + else + count += sprintf(&bufptr[count], "%-25s %-20lu ", + lnames[i].name, rlim[i].rlim_cur); + + if (rlim[i].rlim_max == RLIM_INFINITY) + count += sprintf(&bufptr[count], "%-20s ", "unlimited"); + else + count += sprintf(&bufptr[count], "%-20lu ", + rlim[i].rlim_max); + + if (lnames[i].unit) + count += sprintf(&bufptr[count], "%-10s\n", + lnames[i].unit); + else + count += sprintf(&bufptr[count], "\n"); + } + + return count; +} + /************************************************************************/ /* Here the fs part begins */ /************************************************************************/ @@ -349,18 +424,21 @@ struct proc_mounts { static int mounts_open(struct inode *inode, struct file *file) { struct task_struct *task = get_proc_task(inode); + struct nsproxy *nsp; struct mnt_namespace *ns = NULL; struct proc_mounts *p; int ret = -EINVAL; if (task) { - task_lock(task); - if (task->nsproxy) { - ns = task->nsproxy->mnt_ns; + rcu_read_lock(); + nsp = task_nsproxy(task); + if (nsp) { + ns = nsp->mnt_ns; if (ns) get_mnt_ns(ns); } - task_unlock(task); + rcu_read_unlock(); + put_task_struct(task); } @@ -423,16 +501,20 @@ static int mountstats_open(struct inode *inode, struct file *file) if (!ret) { struct seq_file *m = file->private_data; + struct nsproxy *nsp; struct mnt_namespace *mnt_ns = NULL; struct task_struct *task = get_proc_task(inode); if (task) { - task_lock(task); - if (task->nsproxy) - mnt_ns = task->nsproxy->mnt_ns; - if (mnt_ns) - get_mnt_ns(mnt_ns); - task_unlock(task); + rcu_read_lock(); + nsp = task_nsproxy(task); + if (nsp) { + mnt_ns = nsp->mnt_ns; + if (mnt_ns) + get_mnt_ns(mnt_ns); + } + rcu_read_unlock(); + put_task_struct(task); } @@ -1437,7 +1519,7 @@ static int proc_readfd_common(struct file * filp, void * dirent, struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; struct task_struct *p = get_proc_task(inode); - unsigned int fd, tid, ino; + unsigned int fd, ino; int retval; struct files_struct * files; struct fdtable *fdt; @@ -1446,7 +1528,6 @@ static int proc_readfd_common(struct file * filp, void * dirent, if (!p) goto out_no_task; retval = 0; - tid = p->pid; fd = filp->f_pos; switch (fd) { @@ -1681,7 +1762,6 @@ static int proc_pident_readdir(struct file *filp, const struct pid_entry *ents, unsigned int nents) { int i; - int pid; struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; struct task_struct *task = get_proc_task(inode); @@ -1694,7 +1774,6 @@ static int proc_pident_readdir(struct file *filp, goto out_no_task; ret = 0; - pid = task->pid; i = filp->f_pos; switch (i) { case 0: @@ -1928,14 +2007,14 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer, int buflen) { char tmp[PROC_NUMBUF]; - sprintf(tmp, "%d", current->tgid); + sprintf(tmp, "%d", task_tgid_vnr(current)); return vfs_readlink(dentry,buffer,buflen,tmp); } static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) { char tmp[PROC_NUMBUF]; - sprintf(tmp, "%d", current->tgid); + sprintf(tmp, "%d", task_tgid_vnr(current)); return ERR_PTR(vfs_follow_link(nd,tmp)); } @@ -2101,6 +2180,7 @@ static const struct pid_entry tgid_base_stuff[] = { REG("environ", S_IRUSR, environ), INF("auxv", S_IRUSR, pid_auxv), INF("status", S_IRUGO, pid_status), + INF("limits", S_IRUSR, pid_limits), #ifdef CONFIG_SCHED_DEBUG REG("sched", S_IRUGO|S_IWUSR, pid_sched), #endif @@ -2130,9 +2210,12 @@ static const struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_SCHEDSTATS INF("schedstat", S_IRUGO, pid_schedstat), #endif -#ifdef CONFIG_CPUSETS +#ifdef CONFIG_PROC_PID_CPUSET REG("cpuset", S_IRUGO, cpuset), #endif +#ifdef CONFIG_CGROUPS + REG("cgroup", S_IRUGO, cgroup), +#endif INF("oom_score", S_IRUGO, oom_score), REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust), #ifdef CONFIG_AUDITSYSCALL @@ -2193,27 +2276,27 @@ static const struct inode_operations proc_tgid_base_inode_operations = { * that no dcache entries will exist at process exit time it * just makes it very unlikely that any will persist. */ -void proc_flush_task(struct task_struct *task) +static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) { struct dentry *dentry, *leader, *dir; char buf[PROC_NUMBUF]; struct qstr name; name.name = buf; - name.len = snprintf(buf, sizeof(buf), "%d", task->pid); - dentry = d_hash_and_lookup(proc_mnt->mnt_root, &name); + name.len = snprintf(buf, sizeof(buf), "%d", pid); + dentry = d_hash_and_lookup(mnt->mnt_root, &name); if (dentry) { shrink_dcache_parent(dentry); d_drop(dentry); dput(dentry); } - if (thread_group_leader(task)) + if (tgid == 0) goto out; name.name = buf; - name.len = snprintf(buf, sizeof(buf), "%d", task->tgid); - leader = d_hash_and_lookup(proc_mnt->mnt_root, &name); + name.len = snprintf(buf, sizeof(buf), "%d", tgid); + leader = d_hash_and_lookup(mnt->mnt_root, &name); if (!leader) goto out; @@ -2224,7 +2307,7 @@ void proc_flush_task(struct task_struct *task) goto out_put_leader; name.name = buf; - name.len = snprintf(buf, sizeof(buf), "%d", task->pid); + name.len = snprintf(buf, sizeof(buf), "%d", pid); dentry = d_hash_and_lookup(dir, &name); if (dentry) { shrink_dcache_parent(dentry); @@ -2239,6 +2322,36 @@ out: return; } +/* + * when flushing dentries from proc one need to flush them from global + * proc (proc_mnt) and from all the namespaces' procs this task was seen + * in. this call is supposed to make all this job. + */ + +void proc_flush_task(struct task_struct *task) +{ + int i, leader; + struct pid *pid, *tgid; + struct upid *upid; + + leader = thread_group_leader(task); + proc_flush_task_mnt(proc_mnt, task->pid, leader ? task->tgid : 0); + pid = task_pid(task); + if (pid->level == 0) + return; + + tgid = task_tgid(task); + for (i = 1; i <= pid->level; i++) { + upid = &pid->numbers[i]; + proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, + leader ? 0 : tgid->numbers[i].nr); + } + + upid = &pid->numbers[pid->level]; + if (upid->nr == 1) + pid_ns_release_proc(upid->ns); +} + static struct dentry *proc_pid_instantiate(struct inode *dir, struct dentry * dentry, struct task_struct *task, const void *ptr) @@ -2274,6 +2387,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct struct dentry *result = ERR_PTR(-ENOENT); struct task_struct *task; unsigned tgid; + struct pid_namespace *ns; result = proc_base_lookup(dir, dentry); if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT) @@ -2283,8 +2397,9 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct if (tgid == ~0U) goto out; + ns = dentry->d_sb->s_fs_info; rcu_read_lock(); - task = find_task_by_pid(tgid); + task = find_task_by_pid_ns(tgid, ns); if (task) get_task_struct(task); rcu_read_unlock(); @@ -2301,7 +2416,8 @@ out: * Find the first task with tgid >= tgid * */ -static struct task_struct *next_tgid(unsigned int tgid) +static struct task_struct *next_tgid(unsigned int tgid, + struct pid_namespace *ns) { struct task_struct *task; struct pid *pid; @@ -2309,9 +2425,9 @@ static struct task_struct *next_tgid(unsigned int tgid) rcu_read_lock(); retry: task = NULL; - pid = find_ge_pid(tgid); + pid = find_ge_pid(tgid, ns); if (pid) { - tgid = pid->nr + 1; + tgid = pid_nr_ns(pid, ns) + 1; task = pid_task(pid, PIDTYPE_PID); /* What we to know is if the pid we have find is the * pid of a thread_group_leader. Testing for task @@ -2351,6 +2467,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode); struct task_struct *task; int tgid; + struct pid_namespace *ns; if (!reaper) goto out_no_task; @@ -2361,11 +2478,12 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) goto out; } + ns = filp->f_dentry->d_sb->s_fs_info; tgid = filp->f_pos - TGID_OFFSET; - for (task = next_tgid(tgid); + for (task = next_tgid(tgid, ns); task; - put_task_struct(task), task = next_tgid(tgid + 1)) { - tgid = task->pid; + put_task_struct(task), task = next_tgid(tgid + 1, ns)) { + tgid = task_pid_nr_ns(task, ns); filp->f_pos = tgid + TGID_OFFSET; if (proc_pid_fill_cache(filp, dirent, filldir, task, tgid) < 0) { put_task_struct(task); @@ -2388,6 +2506,7 @@ static const struct pid_entry tid_base_stuff[] = { REG("environ", S_IRUSR, environ), INF("auxv", S_IRUSR, pid_auxv), INF("status", S_IRUGO, pid_status), + INF("limits", S_IRUSR, pid_limits), #ifdef CONFIG_SCHED_DEBUG REG("sched", S_IRUGO|S_IWUSR, pid_sched), #endif @@ -2416,9 +2535,12 @@ static const struct pid_entry tid_base_stuff[] = { #ifdef CONFIG_SCHEDSTATS INF("schedstat", S_IRUGO, pid_schedstat), #endif -#ifdef CONFIG_CPUSETS +#ifdef CONFIG_PROC_PID_CPUSET REG("cpuset", S_IRUGO, cpuset), #endif +#ifdef CONFIG_CGROUPS + REG("cgroup", S_IRUGO, cgroup), +#endif INF("oom_score", S_IRUGO, oom_score), REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust), #ifdef CONFIG_AUDITSYSCALL @@ -2486,6 +2608,7 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry struct task_struct *task; struct task_struct *leader = get_proc_task(dir); unsigned tid; + struct pid_namespace *ns; if (!leader) goto out_no_task; @@ -2494,14 +2617,15 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry if (tid == ~0U) goto out; + ns = dentry->d_sb->s_fs_info; rcu_read_lock(); - task = find_task_by_pid(tid); + task = find_task_by_pid_ns(tid, ns); if (task) get_task_struct(task); rcu_read_unlock(); if (!task) goto out; - if (leader->tgid != task->tgid) + if (!same_thread_group(leader, task)) goto out_drop_task; result = proc_task_instantiate(dir, dentry, task, NULL); @@ -2526,14 +2650,14 @@ out_no_task: * threads past it. */ static struct task_struct *first_tid(struct task_struct *leader, - int tid, int nr) + int tid, int nr, struct pid_namespace *ns) { struct task_struct *pos; rcu_read_lock(); /* Attempt to start with the pid of a thread */ if (tid && (nr > 0)) { - pos = find_task_by_pid(tid); + pos = find_task_by_pid_ns(tid, ns); if (pos && (pos->group_leader == leader)) goto found; } @@ -2602,6 +2726,7 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi ino_t ino; int tid; unsigned long pos = filp->f_pos; /* avoiding "long long" filp->f_pos */ + struct pid_namespace *ns; task = get_proc_task(inode); if (!task) @@ -2635,12 +2760,13 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi /* f_version caches the tgid value that the last readdir call couldn't * return. lseek aka telldir automagically resets f_version to 0. */ + ns = filp->f_dentry->d_sb->s_fs_info; tid = (int)filp->f_version; filp->f_version = 0; - for (task = first_tid(leader, tid, pos - 2); + for (task = first_tid(leader, tid, pos - 2, ns); task; task = next_tid(task), pos++) { - tid = task->pid; + tid = task_pid_nr_ns(task, ns); if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) { /* returning this tgid failed, save it as the first * pid for the next readir call */ diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 99ca00485fc3..abe6a3f04368 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -448,7 +448,7 @@ out_mod: return NULL; } -int proc_fill_super(struct super_block *s, void *data, int silent) +int proc_fill_super(struct super_block *s) { struct inode * root_inode; diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index d6dc72c78bc1..e0d064e9764e 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -91,7 +91,8 @@ static int loadavg_read_proc(char *page, char **start, off_t off, LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), - nr_running(), nr_threads, current->nsproxy->pid_ns->last_pid); + nr_running(), nr_threads, + task_active_pid_ns(current)->last_pid); return proc_calc_metrics(page, start, off, count, eof, len); } diff --git a/fs/proc/root.c b/fs/proc/root.c index cf3046638b09..ec9cb3b6c93b 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -18,32 +18,90 @@ #include <linux/bitops.h> #include <linux/smp_lock.h> #include <linux/mount.h> +#include <linux/pid_namespace.h> #include "internal.h" struct proc_dir_entry *proc_bus, *proc_root_fs, *proc_root_driver; +static int proc_test_super(struct super_block *sb, void *data) +{ + return sb->s_fs_info == data; +} + +static int proc_set_super(struct super_block *sb, void *data) +{ + struct pid_namespace *ns; + + ns = (struct pid_namespace *)data; + sb->s_fs_info = get_pid_ns(ns); + return set_anon_super(sb, NULL); +} + static int proc_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { + int err; + struct super_block *sb; + struct pid_namespace *ns; + struct proc_inode *ei; + if (proc_mnt) { /* Seed the root directory with a pid so it doesn't need * to be special in base.c. I would do this earlier but * the only task alive when /proc is mounted the first time * is the init_task and it doesn't have any pids. */ - struct proc_inode *ei; ei = PROC_I(proc_mnt->mnt_sb->s_root->d_inode); if (!ei->pid) ei->pid = find_get_pid(1); } - return get_sb_single(fs_type, flags, data, proc_fill_super, mnt); + + if (flags & MS_KERNMOUNT) + ns = (struct pid_namespace *)data; + else + ns = current->nsproxy->pid_ns; + + sb = sget(fs_type, proc_test_super, proc_set_super, ns); + if (IS_ERR(sb)) + return PTR_ERR(sb); + + if (!sb->s_root) { + sb->s_flags = flags; + err = proc_fill_super(sb); + if (err) { + up_write(&sb->s_umount); + deactivate_super(sb); + return err; + } + + ei = PROC_I(sb->s_root->d_inode); + if (!ei->pid) { + rcu_read_lock(); + ei->pid = get_pid(find_pid_ns(1, ns)); + rcu_read_unlock(); + } + + sb->s_flags |= MS_ACTIVE; + ns->proc_mnt = mnt; + } + + return simple_set_mnt(mnt, sb); +} + +static void proc_kill_sb(struct super_block *sb) +{ + struct pid_namespace *ns; + + ns = (struct pid_namespace *)sb->s_fs_info; + kill_anon_super(sb); + put_pid_ns(ns); } static struct file_system_type proc_fs_type = { .name = "proc", .get_sb = proc_get_sb, - .kill_sb = kill_anon_super, + .kill_sb = proc_kill_sb, }; void __init proc_root_init(void) @@ -54,12 +112,13 @@ void __init proc_root_init(void) err = register_filesystem(&proc_fs_type); if (err) return; - proc_mnt = kern_mount(&proc_fs_type); + proc_mnt = kern_mount_data(&proc_fs_type, &init_pid_ns); err = PTR_ERR(proc_mnt); if (IS_ERR(proc_mnt)) { unregister_filesystem(&proc_fs_type); return; } + proc_misc_init(); proc_net_init(); @@ -153,6 +212,22 @@ struct proc_dir_entry proc_root = { .parent = &proc_root, }; +int pid_ns_prepare_proc(struct pid_namespace *ns) +{ + struct vfsmount *mnt; + + mnt = kern_mount_data(&proc_fs_type, ns); + if (IS_ERR(mnt)) + return PTR_ERR(mnt); + + return 0; +} + +void pid_ns_release_proc(struct pid_namespace *ns) +{ + mntput(ns->proc_mnt); +} + EXPORT_SYMBOL(proc_symlink); EXPORT_SYMBOL(proc_mkdir); EXPORT_SYMBOL(create_proc_entry); diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index 2a5dd34649b3..16b331dd9913 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -47,7 +47,9 @@ test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)) static inline void get_bit_address(struct super_block *s, - b_blocknr_t block, int *bmap_nr, int *offset) + b_blocknr_t block, + unsigned int *bmap_nr, + unsigned int *offset) { /* It is in the bitmap block number equal to the block * number divided by the number of bits in a block. */ @@ -56,10 +58,10 @@ static inline void get_bit_address(struct super_block *s, *offset = block & ((s->s_blocksize << 3) - 1); } -#ifdef CONFIG_REISERFS_CHECK int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) { - int bmap, offset; + unsigned int bmap, offset; + unsigned int bmap_count = reiserfs_bmap_count(s); if (block == 0 || block >= SB_BLOCK_COUNT(s)) { reiserfs_warning(s, @@ -75,25 +77,26 @@ int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) if (unlikely(test_bit(REISERFS_OLD_FORMAT, &(REISERFS_SB(s)->s_properties)))) { b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1; - if (block >= bmap1 && block <= bmap1 + SB_BMAP_NR(s)) { + if (block >= bmap1 && + block <= bmap1 + bmap_count) { reiserfs_warning(s, "vs: 4019: is_reusable: " "bitmap block %lu(%u) can't be freed or reused", - block, SB_BMAP_NR(s)); + block, bmap_count); return 0; } } else { if (offset == 0) { reiserfs_warning(s, "vs: 4020: is_reusable: " "bitmap block %lu(%u) can't be freed or reused", - block, SB_BMAP_NR(s)); + block, bmap_count); return 0; } } - if (bmap >= SB_BMAP_NR(s)) { + if (bmap >= bmap_count) { reiserfs_warning(s, "vs-4030: is_reusable: there is no so many bitmap blocks: " - "block=%lu, bitmap_nr=%d", block, bmap); + "block=%lu, bitmap_nr=%u", block, bmap); return 0; } @@ -106,12 +109,11 @@ int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) return 1; } -#endif /* CONFIG_REISERFS_CHECK */ /* searches in journal structures for a given block number (bmap, off). If block is found in reiserfs journal it suggests next free block candidate to test. */ -static inline int is_block_in_journal(struct super_block *s, int bmap, int - off, int *next) +static inline int is_block_in_journal(struct super_block *s, unsigned int bmap, + int off, int *next) { b_blocknr_t tmp; @@ -132,8 +134,8 @@ static inline int is_block_in_journal(struct super_block *s, int bmap, int /* it searches for a window of zero bits with given minimum and maximum lengths in one bitmap * block; */ static int scan_bitmap_block(struct reiserfs_transaction_handle *th, - int bmap_n, int *beg, int boundary, int min, - int max, int unfm) + unsigned int bmap_n, int *beg, int boundary, + int min, int max, int unfm) { struct super_block *s = th->t_super; struct reiserfs_bitmap_info *bi = &SB_AP_BITMAP(s)[bmap_n]; @@ -143,8 +145,8 @@ static int scan_bitmap_block(struct reiserfs_transaction_handle *th, BUG_ON(!th->t_trans_id); - RFALSE(bmap_n >= SB_BMAP_NR(s), "Bitmap %d is out of range (0..%d)", - bmap_n, SB_BMAP_NR(s) - 1); + RFALSE(bmap_n >= reiserfs_bmap_count(s), "Bitmap %u is out of " + "range (0..%u)", bmap_n, reiserfs_bmap_count(s) - 1); PROC_INFO_INC(s, scan_bitmap.bmap); /* this is unclear and lacks comments, explain how journal bitmaps work here for the reader. Convey a sense of the design here. What @@ -249,12 +251,12 @@ static int bmap_hash_id(struct super_block *s, u32 id) } else { hash_in = (char *)(&id); hash = keyed_hash(hash_in, 4); - bm = hash % SB_BMAP_NR(s); + bm = hash % reiserfs_bmap_count(s); if (!bm) bm = 1; } /* this can only be true when SB_BMAP_NR = 1 */ - if (bm >= SB_BMAP_NR(s)) + if (bm >= reiserfs_bmap_count(s)) bm = 0; return bm; } @@ -273,7 +275,7 @@ static inline int block_group_used(struct super_block *s, u32 id) * to make a better decision. This favors long-term performace gain * with a better on-disk layout vs. a short term gain of skipping the * read and potentially having a bad placement. */ - if (info->first_zero_hint == 0) { + if (info->free_count == UINT_MAX) { struct buffer_head *bh = reiserfs_read_bitmap_block(s, bm); brelse(bh); } @@ -309,16 +311,16 @@ __le32 reiserfs_choose_packing(struct inode * dir) * bitmap and place new blocks there. Returns number of allocated blocks. */ static int scan_bitmap(struct reiserfs_transaction_handle *th, b_blocknr_t * start, b_blocknr_t finish, - int min, int max, int unfm, unsigned long file_block) + int min, int max, int unfm, sector_t file_block) { int nr_allocated = 0; struct super_block *s = th->t_super; /* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr * - Hans, it is not a block number - Zam. */ - int bm, off; - int end_bm, end_off; - int off_max = s->s_blocksize << 3; + unsigned int bm, off; + unsigned int end_bm, end_off; + unsigned int off_max = s->s_blocksize << 3; BUG_ON(!th->t_trans_id); @@ -328,10 +330,10 @@ static int scan_bitmap(struct reiserfs_transaction_handle *th, get_bit_address(s, *start, &bm, &off); get_bit_address(s, finish, &end_bm, &end_off); - if (bm > SB_BMAP_NR(s)) + if (bm > reiserfs_bmap_count(s)) return 0; - if (end_bm > SB_BMAP_NR(s)) - end_bm = SB_BMAP_NR(s); + if (end_bm > reiserfs_bmap_count(s)) + end_bm = reiserfs_bmap_count(s); /* When the bitmap is more than 10% free, anyone can allocate. * When it's less than 10% free, only files that already use the @@ -385,7 +387,7 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th, struct reiserfs_super_block *rs; struct buffer_head *sbh, *bmbh; struct reiserfs_bitmap_info *apbi; - int nr, offset; + unsigned int nr, offset; BUG_ON(!th->t_trans_id); @@ -397,10 +399,12 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th, get_bit_address(s, block, &nr, &offset); - if (nr >= sb_bmap_nr(rs)) { + if (nr >= reiserfs_bmap_count(s)) { reiserfs_warning(s, "vs-4075: reiserfs_free_block: " - "block %lu is out of range on %s", - block, reiserfs_bdevname(s)); + "block %lu is out of range on %s " + "(nr=%u,max=%u)", block, + reiserfs_bdevname(s), nr, + reiserfs_bmap_count(s)); return; } @@ -434,12 +438,19 @@ void reiserfs_free_block(struct reiserfs_transaction_handle *th, int for_unformatted) { struct super_block *s = th->t_super; - BUG_ON(!th->t_trans_id); RFALSE(!s, "vs-4061: trying to free block on nonexistent device"); - RFALSE(is_reusable(s, block, 1) == 0, - "vs-4071: can not free such block"); + if (!is_reusable(s, block, 1)) + return; + + if (block > sb_block_count(REISERFS_SB(s)->s_rs)) { + reiserfs_panic(th->t_super, "bitmap-4072", + "Trying to free block outside file system " + "boundaries (%lu > %lu)", + block, sb_block_count(REISERFS_SB(s)->s_rs)); + return; + } /* mark it before we clear it, just in case */ journal_mark_freed(th, s, block); _reiserfs_free_block(th, inode, block, for_unformatted); @@ -449,11 +460,11 @@ void reiserfs_free_block(struct reiserfs_transaction_handle *th, static void reiserfs_free_prealloc_block(struct reiserfs_transaction_handle *th, struct inode *inode, b_blocknr_t block) { + BUG_ON(!th->t_trans_id); RFALSE(!th->t_super, "vs-4060: trying to free block on nonexistent device"); - RFALSE(is_reusable(th->t_super, block, 1) == 0, - "vs-4070: can not free such block"); - BUG_ON(!th->t_trans_id); + if (!is_reusable(th->t_super, block, 1)) + return; _reiserfs_free_block(th, inode, block, 1); } @@ -1207,27 +1218,22 @@ void reiserfs_cache_bitmap_metadata(struct super_block *sb, { unsigned long *cur = (unsigned long *)(bh->b_data + bh->b_size); - info->first_zero_hint = 1 << (sb->s_blocksize_bits + 3); + /* The first bit must ALWAYS be 1 */ + BUG_ON(!reiserfs_test_le_bit(0, (unsigned long *)bh->b_data)); + + info->free_count = 0; while (--cur >= (unsigned long *)bh->b_data) { - int base = ((char *)cur - bh->b_data) << 3; + int i; /* 0 and ~0 are special, we can optimize for them */ - if (*cur == 0) { - info->first_zero_hint = base; + if (*cur == 0) info->free_count += BITS_PER_LONG; - } else if (*cur != ~0L) { /* A mix, investigate */ - int b; - for (b = BITS_PER_LONG - 1; b >= 0; b--) { - if (!reiserfs_test_le_bit(b, cur)) { - info->first_zero_hint = base + b; + else if (*cur != ~0L) /* A mix, investigate */ + for (i = BITS_PER_LONG - 1; i >= 0; i--) + if (!reiserfs_test_le_bit(i, cur)) info->free_count++; - } - } - } } - /* The first bit must ALWAYS be 1 */ - BUG_ON(info->first_zero_hint == 0); } struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, @@ -1257,7 +1263,7 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, BUG_ON(!buffer_uptodate(bh)); BUG_ON(atomic_read(&bh->b_count) == 0); - if (info->first_zero_hint == 0) + if (info->free_count == UINT_MAX) reiserfs_cache_bitmap_metadata(sb, bh, info); } @@ -1267,12 +1273,13 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, int reiserfs_init_bitmap_cache(struct super_block *sb) { struct reiserfs_bitmap_info *bitmap; + unsigned int bmap_nr = reiserfs_bmap_count(sb); - bitmap = vmalloc(sizeof (*bitmap) * SB_BMAP_NR(sb)); + bitmap = vmalloc(sizeof(*bitmap) * bmap_nr); if (bitmap == NULL) return -ENOMEM; - memset(bitmap, 0, sizeof (*bitmap) * SB_BMAP_NR(sb)); + memset(bitmap, 0xff, sizeof(*bitmap) * bmap_nr); SB_AP_BITMAP(sb) = bitmap; diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 0804289d355d..a991af96f3f0 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -199,7 +199,7 @@ static inline void set_block_dev_mapped(struct buffer_head *bh, // files which were created in the earlier version can not be longer, // than 2 gb // -static int file_capable(struct inode *inode, long block) +static int file_capable(struct inode *inode, sector_t block) { if (get_inode_item_key_version(inode) != KEY_FORMAT_3_5 || // it is new file. block < (1 << (31 - inode->i_sb->s_blocksize_bits))) // old file, but 'block' is inside of 2gb @@ -242,7 +242,7 @@ static int restart_transaction(struct reiserfs_transaction_handle *th, // Please improve the english/clarity in the comment above, as it is // hard to understand. -static int _get_block_create_0(struct inode *inode, long block, +static int _get_block_create_0(struct inode *inode, sector_t block, struct buffer_head *bh_result, int args) { INITIALIZE_PATH(path); @@ -250,7 +250,7 @@ static int _get_block_create_0(struct inode *inode, long block, struct buffer_head *bh; struct item_head *ih, tmp_ih; int fs_gen; - int blocknr; + b_blocknr_t blocknr; char *p = NULL; int chars; int ret; @@ -569,7 +569,7 @@ static int convert_tail_for_hole(struct inode *inode, } static inline int _allocate_block(struct reiserfs_transaction_handle *th, - long block, + sector_t block, struct inode *inode, b_blocknr_t * allocated_block_nr, struct treepath *path, int flags) diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 4cad9e75ef56..bb05a3e51b93 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -219,11 +219,12 @@ static void allocate_bitmap_nodes(struct super_block *p_s_sb) } } -static int set_bit_in_list_bitmap(struct super_block *p_s_sb, int block, +static int set_bit_in_list_bitmap(struct super_block *p_s_sb, + b_blocknr_t block, struct reiserfs_list_bitmap *jb) { - int bmap_nr = block / (p_s_sb->s_blocksize << 3); - int bit_nr = block % (p_s_sb->s_blocksize << 3); + unsigned int bmap_nr = block / (p_s_sb->s_blocksize << 3); + unsigned int bit_nr = block % (p_s_sb->s_blocksize << 3); if (!jb->bitmaps[bmap_nr]) { jb->bitmaps[bmap_nr] = get_bitmap_node(p_s_sb); @@ -239,7 +240,7 @@ static void cleanup_bitmap_list(struct super_block *p_s_sb, if (jb->bitmaps == NULL) return; - for (i = 0; i < SB_BMAP_NR(p_s_sb); i++) { + for (i = 0; i < reiserfs_bmap_count(p_s_sb); i++) { if (jb->bitmaps[i]) { free_bitmap_node(p_s_sb, jb->bitmaps[i]); jb->bitmaps[i] = NULL; @@ -289,7 +290,7 @@ static int free_bitmap_nodes(struct super_block *p_s_sb) */ int reiserfs_allocate_list_bitmaps(struct super_block *p_s_sb, struct reiserfs_list_bitmap *jb_array, - int bmap_nr) + unsigned int bmap_nr) { int i; int failed = 0; @@ -483,7 +484,7 @@ static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct ** */ int reiserfs_in_journal(struct super_block *p_s_sb, - int bmap_nr, int bit_nr, int search_all, + unsigned int bmap_nr, int bit_nr, int search_all, b_blocknr_t * next_zero_bit) { struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); @@ -1013,7 +1014,7 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) { int i; - int bn; + b_blocknr_t bn; struct buffer_head *tbh = NULL; unsigned long trans_id = jl->j_trans_id; struct reiserfs_journal *journal = SB_JOURNAL(s); @@ -2307,8 +2308,9 @@ static int journal_read_transaction(struct super_block *p_s_sb, Right now it is only used from journal code. But later we might use it from other places. Note: Do not use journal_getblk/sb_getblk functions here! */ -static struct buffer_head *reiserfs_breada(struct block_device *dev, int block, - int bufsize, unsigned int max_block) +static struct buffer_head *reiserfs_breada(struct block_device *dev, + b_blocknr_t block, int bufsize, + b_blocknr_t max_block) { struct buffer_head *bhlist[BUFNR]; unsigned int blocks = BUFNR; @@ -2732,7 +2734,7 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, journal->j_persistent_trans = 0; if (reiserfs_allocate_list_bitmaps(p_s_sb, journal->j_list_bitmap, - SB_BMAP_NR(p_s_sb))) + reiserfs_bmap_count(p_s_sb))) goto free_and_return; allocate_bitmap_nodes(p_s_sb); @@ -2740,7 +2742,7 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) = (old_format ? REISERFS_OLD_DISK_OFFSET_IN_BYTES / p_s_sb->s_blocksize + - SB_BMAP_NR(p_s_sb) + + reiserfs_bmap_count(p_s_sb) + 1 : REISERFS_DISK_OFFSET_IN_BYTES / p_s_sb->s_blocksize + 2); diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c index bc808a91eeaa..5e7388b32d02 100644 --- a/fs/reiserfs/prints.c +++ b/fs/reiserfs/prints.c @@ -356,13 +356,11 @@ extern struct tree_balance *cur_tb; void reiserfs_panic(struct super_block *sb, const char *fmt, ...) { do_reiserfs_warning(fmt); - printk(KERN_EMERG "REISERFS: panic (device %s): %s\n", - reiserfs_bdevname(sb), error_buf); - BUG(); - /* this is not actually called, but makes reiserfs_panic() "noreturn" */ - panic("REISERFS: panic (device %s): %s\n", - reiserfs_bdevname(sb), error_buf); + dump_stack(); + + panic(KERN_EMERG "REISERFS: panic (device %s): %s\n", + reiserfs_bdevname(sb), error_buf); } void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...) diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c index 976cc7887a0d..f71c3948edef 100644 --- a/fs/reiserfs/resize.c +++ b/fs/reiserfs/resize.c @@ -61,7 +61,8 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) } /* count used bits in last bitmap block */ - block_r = SB_BLOCK_COUNT(s) - (SB_BMAP_NR(s) - 1) * s->s_blocksize * 8; + block_r = SB_BLOCK_COUNT(s) - + (reiserfs_bmap_count(s) - 1) * s->s_blocksize * 8; /* count bitmap blocks in new fs */ bmap_nr_new = block_count_new / (s->s_blocksize * 8); @@ -73,7 +74,7 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) /* save old values */ block_count = SB_BLOCK_COUNT(s); - bmap_nr = SB_BMAP_NR(s); + bmap_nr = reiserfs_bmap_count(s); /* resizing of reiserfs bitmaps (journal and real), if needed */ if (bmap_nr_new > bmap_nr) { @@ -119,7 +120,7 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) return -ENOMEM; } memset(bitmap, 0, - sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(s)); + sizeof(struct reiserfs_bitmap_info) * bmap_nr_new); for (i = 0; i < bmap_nr; i++) bitmap[i] = old_bitmap[i]; @@ -143,7 +144,6 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) mark_buffer_dirty(bh); sync_dirty_buffer(bh); // update bitmap_info stuff - bitmap[i].first_zero_hint = 1; bitmap[i].free_count = sb_blocksize(sb) * 8 - 1; brelse(bh); } @@ -173,8 +173,6 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) for (i = block_r; i < s->s_blocksize * 8; i++) reiserfs_test_and_clear_le_bit(i, bh->b_data); info->free_count += s->s_blocksize * 8 - block_r; - if (!info->first_zero_hint) - info->first_zero_hint = block_r; journal_mark_dirty(&th, s, bh); brelse(bh); @@ -196,9 +194,6 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) brelse(bh); info->free_count -= s->s_blocksize * 8 - block_r_new; - /* Extreme case where last bitmap is the only valid block in itself. */ - if (!info->free_count) - info->first_zero_hint = 0; /* update super */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); free_blocks = SB_FREE_BLOCKS(s); @@ -206,7 +201,7 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) free_blocks + (block_count_new - block_count - (bmap_nr_new - bmap_nr))); PUT_SB_BLOCK_COUNT(s, block_count_new); - PUT_SB_BMAP_NR(s, bmap_nr_new); + PUT_SB_BMAP_NR(s, bmap_would_wrap(bmap_nr_new) ? : bmap_nr_new); s->s_dirt = 1; journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 981027d1187b..ca41567d7890 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -559,7 +559,7 @@ static int is_tree_node(struct buffer_head *bh, int level) /* The function is NOT SCHEDULE-SAFE! */ static void search_by_key_reada(struct super_block *s, struct buffer_head **bh, - unsigned long *b, int num) + b_blocknr_t *b, int num) { int i, j; @@ -611,7 +611,7 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* DISK_LEAF_NODE_LEVEL */ ) { - int n_block_number; + b_blocknr_t n_block_number; int expected_level; struct buffer_head *p_s_bh; struct path_element *p_s_last_element; @@ -619,7 +619,7 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* int right_neighbor_of_leaf_node; int fs_gen; struct buffer_head *reada_bh[SEARCH_BY_KEY_READA]; - unsigned long reada_blocks[SEARCH_BY_KEY_READA]; + b_blocknr_t reada_blocks[SEARCH_BY_KEY_READA]; int reada_count = 0; #ifdef CONFIG_REISERFS_CHECK diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index b82897ae090b..57adfe90d5ae 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1725,6 +1725,21 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) set_sb_umount_state(rs, REISERFS_ERROR_FS); set_sb_fs_state(rs, 0); + /* Clear out s_bmap_nr if it would wrap. We can handle this + * case, but older revisions can't. This will cause the + * file system to fail mount on those older implementations, + * avoiding corruption. -jeffm */ + if (bmap_would_wrap(reiserfs_bmap_count(s)) && + sb_bmap_nr(rs) != 0) { + reiserfs_warning(s, "super-2030: This file system " + "claims to use %u bitmap blocks in " + "its super block, but requires %u. " + "Clearing to zero.", sb_bmap_nr(rs), + reiserfs_bmap_count(s)); + + set_sb_bmap_nr(rs, 0); + } + if (old_format_only(s)) { /* filesystem of format 3.5 either with standard or non-standard journal */ diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index fab4b9b2664f..1597f6b649e0 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -484,7 +484,7 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, /* Resize it so we're ok to write there */ newattrs.ia_size = buffer_size; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - mutex_lock(&xinode->i_mutex); + mutex_lock_nested(&xinode->i_mutex, I_MUTEX_XATTR); err = notify_change(fp->f_path.dentry, &newattrs); if (err) goto out_filp; @@ -1223,7 +1223,8 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags) if (!IS_ERR(dentry)) { if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) { struct inode *inode = dentry->d_parent->d_inode; - mutex_lock(&inode->i_mutex); + mutex_lock_nested(&inode->i_mutex, + I_MUTEX_XATTR); err = inode->i_op->mkdir(inode, dentry, 0700); mutex_unlock(&inode->i_mutex); if (err) { diff --git a/fs/select.c b/fs/select.c index 7dede89658f5..47f47925aea2 100644 --- a/fs/select.c +++ b/fs/select.c @@ -177,11 +177,6 @@ get_max: return max; } -#define BIT(i) (1UL << ((i)&(__NFDBITS-1))) -#define MEM(i,m) ((m)+(unsigned)(i)/__NFDBITS) -#define ISSET(i,m) (((i)&*(m)) != 0) -#define SET(i,m) (*(m) |= (i)) - #define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR) #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) #define POLLEX_SET (POLLPRI) diff --git a/fs/super.c b/fs/super.c index 1bfcca2104be..d28fde7e1cfb 100644 --- a/fs/super.c +++ b/fs/super.c @@ -40,10 +40,6 @@ #include <asm/uaccess.h> -void get_filesystem(struct file_system_type *fs); -void put_filesystem(struct file_system_type *fs); -struct file_system_type *get_fs_type(const char *name); - LIST_HEAD(super_blocks); DEFINE_SPINLOCK(sb_lock); @@ -336,21 +332,21 @@ struct super_block *sget(struct file_system_type *type, void *data) { struct super_block *s = NULL; - struct list_head *p; + struct super_block *old; int err; retry: spin_lock(&sb_lock); - if (test) list_for_each(p, &type->fs_supers) { - struct super_block *old; - old = list_entry(p, struct super_block, s_instances); - if (!test(old, data)) - continue; - if (!grab_super(old)) - goto retry; - if (s) - destroy_super(s); - return old; + if (test) { + list_for_each_entry(old, &type->fs_supers, s_instances) { + if (!test(old, data)) + continue; + if (!grab_super(old)) + goto retry; + if (s) + destroy_super(s); + return old; + } } if (!s) { spin_unlock(&sb_lock); @@ -948,9 +944,9 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data) return mnt; } -struct vfsmount *kern_mount(struct file_system_type *type) +struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) { - return vfs_kern_mount(type, 0, type->name, NULL); + return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data); } -EXPORT_SYMBOL(kern_mount); +EXPORT_SYMBOL_GPL(kern_mount_data); diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c index 726449d4fd22..3586c7a28d2c 100644 --- a/fs/xfs/linux-2.6/xfs_export.c +++ b/fs/xfs/linux-2.6/xfs_export.c @@ -54,8 +54,8 @@ xfs_fs_decode_fh( struct dentry *de), void *context) { - xfs_fid2_t ifid; - xfs_fid2_t pfid; + xfs_fid_t ifid; + xfs_fid_t pfid; void *parent = NULL; int is64 = 0; __u32 *p = fh; @@ -144,7 +144,7 @@ xfs_fs_get_dentry( struct dentry *result; int error; - error = xfs_vget(XFS_M(sb), &vp, (fid_t *)data); + error = xfs_vget(XFS_M(sb), &vp, data); if (error || vp == NULL) return ERR_PTR(-ESTALE) ; diff --git a/fs/xfs/linux-2.6/xfs_export.h b/fs/xfs/linux-2.6/xfs_export.h index e794ca4efc76..2f36071a86f7 100644 --- a/fs/xfs/linux-2.6/xfs_export.h +++ b/fs/xfs/linux-2.6/xfs_export.h @@ -71,13 +71,13 @@ xfs_fileid_length(int hasparent, int is64) /* * Decode encoded inode information (either for the inode itself - * or the parent) into an xfs_fid2_t structure. Advances and + * or the parent) into an xfs_fid_t structure. Advances and * returns the new data pointer */ static inline __u32 * -xfs_fileid_decode_fid2(__u32 *p, xfs_fid2_t *fid, int is64) +xfs_fileid_decode_fid2(__u32 *p, xfs_fid_t *fid, int is64) { - fid->fid_len = sizeof(xfs_fid2_t) - sizeof(fid->fid_len); + fid->fid_len = sizeof(xfs_fid_t) - sizeof(fid->fid_len); fid->fid_pad = 0; fid->fid_ino = *p++; #if XFS_BIG_INUMS diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index ffec630e7db7..2b34bad48b07 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -152,11 +152,11 @@ xfs_find_handle( lock_mode = xfs_ilock_map_shared(ip); /* fill in fid section of handle from inode */ - handle.ha_fid.xfs_fid_len = sizeof(xfs_fid_t) - - sizeof(handle.ha_fid.xfs_fid_len); - handle.ha_fid.xfs_fid_pad = 0; - handle.ha_fid.xfs_fid_gen = ip->i_d.di_gen; - handle.ha_fid.xfs_fid_ino = ip->i_ino; + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - + sizeof(handle.ha_fid.fid_len); + handle.ha_fid.fid_pad = 0; + handle.ha_fid.fid_gen = ip->i_d.di_gen; + handle.ha_fid.fid_ino = ip->i_ino; xfs_iunlock_map_shared(ip, lock_mode); @@ -222,10 +222,10 @@ xfs_vget_fsop_handlereq( if (hlen < sizeof(*handlep)) memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen); if (hlen > sizeof(handlep->ha_fsid)) { - if (handlep->ha_fid.xfs_fid_len != - (hlen - sizeof(handlep->ha_fsid) - - sizeof(handlep->ha_fid.xfs_fid_len)) - || handlep->ha_fid.xfs_fid_pad) + if (handlep->ha_fid.fid_len != + (hlen - sizeof(handlep->ha_fsid) - + sizeof(handlep->ha_fid.fid_len)) || + handlep->ha_fid.fid_pad) return XFS_ERROR(EINVAL); } @@ -233,9 +233,9 @@ xfs_vget_fsop_handlereq( * Crack the handle, obtain the inode # & generation # */ xfid = (struct xfs_fid *)&handlep->ha_fid; - if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) { - ino = xfid->xfs_fid_ino; - igen = xfid->xfs_fid_gen; + if (xfid->fid_len == sizeof(*xfid) - sizeof(xfid->fid_len)) { + ino = xfid->fid_ino; + igen = xfid->fid_gen; } else { return XFS_ERROR(EINVAL); } diff --git a/fs/xfs/xfs_dmops.c b/fs/xfs/xfs_dmops.c index 6cd5704258a2..a1e55fb9d5dd 100644 --- a/fs/xfs/xfs_dmops.c +++ b/fs/xfs/xfs_dmops.c @@ -41,29 +41,16 @@ int xfs_dmops_get(struct xfs_mount *mp, struct xfs_mount_args *args) { if (args->flags & XFSMNT_DMAPI) { - struct xfs_dmops *ops; - - ops = symbol_get(xfs_dmcore_xfs); - if (!ops) { - request_module("xfs_dmapi"); - ops = symbol_get(xfs_dmcore_xfs); - } - - if (!ops) { - cmn_err(CE_WARN, "XFS: no dmapi support available."); - return EINVAL; - } - mp->m_dm_ops = ops; - } else { - mp->m_dm_ops = &xfs_dmcore_stub; + cmn_err(CE_WARN, + "XFS: dmapi support not available in this kernel."); + return EINVAL; } + mp->m_dm_ops = &xfs_dmcore_stub; return 0; } void xfs_dmops_put(struct xfs_mount *mp) { - if (mp->m_dm_ops != &xfs_dmcore_stub) - symbol_put(xfs_dmcore_xfs); } diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index ec3c9c27e0de..aab966276517 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h @@ -389,30 +389,13 @@ typedef struct xfs_fsop_attrmulti_handlereq { */ typedef struct { __u32 val[2]; } xfs_fsid_t; /* file system id type */ - -#ifndef HAVE_FID -#define MAXFIDSZ 46 - -typedef struct fid { - __u16 fid_len; /* length of data in bytes */ - unsigned char fid_data[MAXFIDSZ]; /* data (fid_len worth) */ -} fid_t; -#endif - typedef struct xfs_fid { - __u16 xfs_fid_len; /* length of remainder */ - __u16 xfs_fid_pad; - __u32 xfs_fid_gen; /* generation number */ - __u64 xfs_fid_ino; /* 64 bits inode number */ + __u16 fid_len; /* length of remainder */ + __u16 fid_pad; + __u32 fid_gen; /* generation number */ + __u64 fid_ino; /* 64 bits inode number */ } xfs_fid_t; -typedef struct xfs_fid2 { - __u16 fid_len; /* length of remainder */ - __u16 fid_pad; /* padding, must be zero */ - __u32 fid_gen; /* generation number */ - __u64 fid_ino; /* inode number */ -} xfs_fid2_t; - typedef struct xfs_handle { union { __s64 align; /* force alignment of ha_fid */ @@ -422,9 +405,9 @@ typedef struct xfs_handle { } xfs_handle_t; #define ha_fsid ha_u._ha_fsid -#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.xfs_fid_pad \ +#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \ - (char *) &(handle)) \ - + (handle).ha_fid.xfs_fid_len) + + (handle).ha_fid.fid_len) /* * Flags for going down operation diff --git a/fs/xfs/xfs_qmops.c b/fs/xfs/xfs_qmops.c index c266a0184b42..2ec1d8a27352 100644 --- a/fs/xfs/xfs_qmops.c +++ b/fs/xfs/xfs_qmops.c @@ -135,19 +135,13 @@ int xfs_qmops_get(struct xfs_mount *mp, struct xfs_mount_args *args) { if (args->flags & (XFSMNT_UQUOTA | XFSMNT_PQUOTA | XFSMNT_GQUOTA)) { - struct xfs_qmops *ops; - - ops = symbol_get(xfs_qmcore_xfs); - if (!ops) { - request_module("xfs_quota"); - ops = symbol_get(xfs_qmcore_xfs); - } - - if (!ops) { - cmn_err(CE_WARN, "XFS: no quota support available."); - return EINVAL; - } - mp->m_qm_ops = ops; +#ifdef CONFIG_XFS_QUOTA + mp->m_qm_ops = &xfs_qmcore_xfs; +#else + cmn_err(CE_WARN, + "XFS: qouta support not available in this kernel."); + return EINVAL; +#endif } else { mp->m_qm_ops = &xfs_qmcore_stub; } @@ -158,6 +152,4 @@ xfs_qmops_get(struct xfs_mount *mp, struct xfs_mount_args *args) void xfs_qmops_put(struct xfs_mount *mp) { - if (mp->m_qm_ops != &xfs_qmcore_stub) - symbol_put(xfs_qmcore_xfs); } diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index a5a8454f2a63..a1544597bcd3 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -1635,9 +1635,8 @@ int xfs_vget( xfs_mount_t *mp, bhv_vnode_t **vpp, - fid_t *fidp) + xfs_fid_t *xfid) { - xfs_fid_t *xfid = (struct xfs_fid *)fidp; xfs_inode_t *ip; int error; xfs_ino_t ino; @@ -1647,11 +1646,11 @@ xfs_vget( * Invalid. Since handles can be created in user space and passed in * via gethandle(), this is not cause for a panic. */ - if (xfid->xfs_fid_len != sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) + if (xfid->fid_len != sizeof(*xfid) - sizeof(xfid->fid_len)) return XFS_ERROR(EINVAL); - ino = xfid->xfs_fid_ino; - igen = xfid->xfs_fid_gen; + ino = xfid->fid_ino; + igen = xfid->fid_gen; /* * NFS can sometimes send requests for ino 0. Fail them gracefully. diff --git a/fs/xfs/xfs_vfsops.h b/fs/xfs/xfs_vfsops.h index bc99e3eb7dbb..a592fe02a339 100644 --- a/fs/xfs/xfs_vfsops.h +++ b/fs/xfs/xfs_vfsops.h @@ -2,7 +2,7 @@ #define _XFS_VFSOPS_H 1 struct cred; -struct fid; +struct xfs_fid; struct inode; struct kstatfs; struct xfs_mount; @@ -17,7 +17,7 @@ int xfs_root(struct xfs_mount *mp, bhv_vnode_t **vpp); int xfs_statvfs(struct xfs_mount *mp, struct kstatfs *statp, bhv_vnode_t *vp); int xfs_sync(struct xfs_mount *mp, int flags); -int xfs_vget(struct xfs_mount *mp, bhv_vnode_t **vpp, struct fid *fidp); +int xfs_vget(struct xfs_mount *mp, bhv_vnode_t **vpp, struct xfs_fid *xfid); int xfs_parseargs(struct xfs_mount *mp, char *options, struct xfs_mount_args *args, int update); int xfs_showargs(struct xfs_mount *mp, struct seq_file *m); diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 5e3c57ca9981..efd5aff9eaf6 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -3466,23 +3466,14 @@ std_return: } -/* - * xfs_fid2 - * - * A fid routine that takes a pointer to a previously allocated - * fid structure (like xfs_fast_fid) but uses a 64 bit inode number. - */ int xfs_fid2( xfs_inode_t *ip, - fid_t *fidp) + xfs_fid_t *xfid) { - xfs_fid2_t *xfid = (xfs_fid2_t *)fidp; - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); - ASSERT(sizeof(fid_t) >= sizeof(xfs_fid2_t)); - xfid->fid_len = sizeof(xfs_fid2_t) - sizeof(xfid->fid_len); + xfid->fid_len = sizeof(xfs_fid_t) - sizeof(xfid->fid_len); xfid->fid_pad = 0; /* * use memcpy because the inode is a long long and there's no diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index f36e74f2f0c2..b7e461c40cfb 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h @@ -39,7 +39,7 @@ int xfs_readdir(struct xfs_inode *dp, void *dirent, size_t bufsize, int xfs_symlink(struct xfs_inode *dp, bhv_vname_t *dentry, char *target_path, mode_t mode, bhv_vnode_t **vpp, struct cred *credp); -int xfs_fid2(struct xfs_inode *ip, fid_t *fidp); +int xfs_fid2(struct xfs_inode *ip, struct xfs_fid *xfid); int xfs_rwlock(struct xfs_inode *ip, bhv_vrwlock_t locktype); void xfs_rwunlock(struct xfs_inode *ip, bhv_vrwlock_t locktype); int xfs_inode_flush(struct xfs_inode *ip, int flags); |