From 26a21b980b1897b11fd7f9ba4bf6060c9e15df10 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 31 May 2006 18:05:34 +0000 Subject: [PATCH 001/556] [CIFS] Cleanup extra whitespace in dmesg logging. Update cifs change log --- fs/cifs/CHANGES | 5 ++++- fs/cifs/asn1.c | 10 +++++----- fs/cifs/cifssmb.c | 2 +- fs/cifs/dir.c | 2 +- fs/cifs/file.c | 18 +++++++++--------- fs/cifs/inode.c | 24 ++++++++++++------------ fs/cifs/link.c | 7 +++---- fs/cifs/readdir.c | 2 +- fs/cifs/transport.c | 3 +-- 9 files changed, 37 insertions(+), 36 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 7271bb0257f6..953d2f7f88b0 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -3,7 +3,10 @@ Version 1.43 POSIX locking to servers which support CIFS POSIX Extensions (disabled by default controlled by proc/fs/cifs/Experimental). Handle conversion of long share names (especially Asian languages) -to Unicode during mount. +to Unicode during mount. Fix memory leak in sess struct on reconnect. +Fix rare oops after acpi suspend. Fix O_TRUNC opens to overwrite on +cifs open which helps rare case when setpathinfo fails or server does +not support it. Version 1.42 ------------ diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 086ae8f4a207..031cdf293256 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -467,7 +467,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, asn1_open(&ctx, security_blob, length); if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { - cFYI(1, ("Error decoding negTokenInit header ")); + cFYI(1, ("Error decoding negTokenInit header")); return 0; } else if ((cls != ASN1_APL) || (con != ASN1_CON) || (tag != ASN1_EOC)) { @@ -495,7 +495,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, } if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { - cFYI(1, ("Error decoding negTokenInit ")); + cFYI(1, ("Error decoding negTokenInit")); return 0; } else if ((cls != ASN1_CTX) || (con != ASN1_CON) || (tag != ASN1_EOC)) { @@ -505,7 +505,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, } if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { - cFYI(1, ("Error decoding negTokenInit ")); + cFYI(1, ("Error decoding negTokenInit")); return 0; } else if ((cls != ASN1_UNI) || (con != ASN1_CON) || (tag != ASN1_SEQ)) { @@ -515,7 +515,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, } if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { - cFYI(1, ("Error decoding 2nd part of negTokenInit ")); + cFYI(1, ("Error decoding 2nd part of negTokenInit")); return 0; } else if ((cls != ASN1_CTX) || (con != ASN1_CON) || (tag != ASN1_EOC)) { @@ -527,7 +527,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, if (asn1_header_decode (&ctx, &sequence_end, &cls, &con, &tag) == 0) { - cFYI(1, ("Error decoding 2nd part of negTokenInit ")); + cFYI(1, ("Error decoding 2nd part of negTokenInit")); return 0; } else if ((cls != ASN1_UNI) || (con != ASN1_CON) || (tag != ASN1_SEQ)) { diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 925881e00ff2..f00369277c06 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2239,7 +2239,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, } symlinkinfo[buflen] = 0; /* just in case so the caller does not go off the end of the buffer */ - cFYI(1,("readlink result - %s ",symlinkinfo)); + cFYI(1,("readlink result - %s",symlinkinfo)); } } qreparse_out: diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 82315edc77d7..57bdf7f734bf 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -191,7 +191,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } if (rc) { - cFYI(1, ("cifs_create returned 0x%x ", rc)); + cFYI(1, ("cifs_create returned 0x%x", rc)); } else { /* If Open reported that we actually created a file then we now have to set the mode if possible */ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e2b4ce1dad66..379369ecda96 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -201,7 +201,7 @@ int cifs_open(struct inode *inode, struct file *file) } else { if (file->f_flags & O_EXCL) cERROR(1, ("could not find file instance for " - "new file %p ", file)); + "new file %p", file)); } } @@ -272,7 +272,7 @@ int cifs_open(struct inode *inode, struct file *file) & CIFS_MOUNT_MAP_SPECIAL_CHR); } if (rc) { - cFYI(1, ("cifs_open returned 0x%x ", rc)); + cFYI(1, ("cifs_open returned 0x%x", rc)); goto out; } file->private_data = @@ -409,8 +409,8 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { up(&pCifsFile->fh_sem); - cFYI(1, ("cifs_open returned 0x%x ", rc)); - cFYI(1, ("oplock: %d ", oplock)); + cFYI(1, ("cifs_open returned 0x%x", rc)); + cFYI(1, ("oplock: %d", oplock)); } else { pCifsFile->netfid = netfid; pCifsFile->invalidHandle = FALSE; @@ -531,7 +531,7 @@ int cifs_closedir(struct inode *inode, struct file *file) (struct cifsFileInfo *)file->private_data; char *ptmp; - cFYI(1, ("Closedir inode = 0x%p with ", inode)); + cFYI(1, ("Closedir inode = 0x%p", inode)); xid = GetXid(); @@ -605,7 +605,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) } if (pfLock->fl_flags & FL_ACCESS) cFYI(1, ("Process suspended by mandatory locking - " - "not implemented yet ")); + "not implemented yet")); if (pfLock->fl_flags & FL_LEASE) cFYI(1, ("Lease on file - not implemented yet")); if (pfLock->fl_flags & @@ -1377,7 +1377,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) xid = GetXid(); - cFYI(1, ("Sync file - name: %s datasync: 0x%x ", + cFYI(1, ("Sync file - name: %s datasync: 0x%x", dentry->d_name.name, datasync)); rc = filemap_fdatawrite(inode->i_mapping); @@ -1406,7 +1406,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) /* fill in rpages then result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */ -/* cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); +/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index)); #if 0 if (rc < 0) @@ -1838,7 +1838,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page, if (rc < 0) goto io_error; else - cFYI(1, ("Bytes read %d ",rc)); + cFYI(1, ("Bytes read %d",rc)); file->f_dentry->d_inode->i_atime = current_fs_time(file->f_dentry->d_inode->i_sb); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 4093764ef461..77a9e2f912fd 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -41,7 +41,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, char *tmp_path; pTcon = cifs_sb->tcon; - cFYI(1, ("Getting info on %s ", search_path)); + cFYI(1, ("Getting info on %s", search_path)); /* could have done a find first instead but this returns more info */ rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -97,9 +97,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode = *pinode; cifsInfo = CIFS_I(inode); - cFYI(1, ("Old time %ld ", cifsInfo->time)); + cFYI(1, ("Old time %ld", cifsInfo->time)); cifsInfo->time = jiffies; - cFYI(1, ("New time %ld ", cifsInfo->time)); + cFYI(1, ("New time %ld", cifsInfo->time)); /* this is ok to set on every inode revalidate */ atomic_set(&cifsInfo->inUse,1); @@ -421,23 +421,23 @@ int cifs_get_inode_info(struct inode **pinode, inode = *pinode; cifsInfo = CIFS_I(inode); cifsInfo->cifsAttrs = attr; - cFYI(1, ("Old time %ld ", cifsInfo->time)); + cFYI(1, ("Old time %ld", cifsInfo->time)); cifsInfo->time = jiffies; - cFYI(1, ("New time %ld ", cifsInfo->time)); + cFYI(1, ("New time %ld", cifsInfo->time)); /* blksize needs to be multiple of two. So safer to default to blksize and blkbits set in superblock so 2**blkbits and blksize will match rather than setting to: (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ - /* Linux can not store file creation time unfortunately so we ignore it */ + /* Linux can not store file creation time so ignore it */ inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); inode->i_mtime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); - cFYI(0, ("Attributes came in as 0x%x ", attr)); + cFYI(0, ("Attributes came in as 0x%x", attr)); /* set default mode. will override for dirs below */ if (atomic_read(&cifsInfo->inUse) == 0) @@ -731,7 +731,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { - cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); + cFYI(1, ("cifs_mkdir returned 0x%x", rc)); d_drop(direntry); } else { inode->i_nlink++; @@ -798,7 +798,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) char *full_path = NULL; struct cifsInodeInfo *cifsInode; - cFYI(1, ("cifs_rmdir, inode = 0x%p with ", inode)); + cFYI(1, ("cifs_rmdir, inode = 0x%p", inode)); xid = GetXid(); @@ -1121,7 +1121,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) xid = GetXid(); - cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x ", + cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x", direntry->d_name.name, attrs->ia_valid)); cifs_sb = CIFS_SB(direntry->d_inode->i_sb); @@ -1289,7 +1289,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) it may be useful to Windows - but we do not want to set ctime unless some other timestamp is changing */ - cFYI(1, ("CIFS - CTIME changed ")); + cFYI(1, ("CIFS - CTIME changed")); time_buf.ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); } else @@ -1356,7 +1356,7 @@ cifs_setattr_exit: void cifs_delete_inode(struct inode *inode) { - cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode)); + cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode)); /* may have to add back in if and when safe distributed caching of directories added e.g. via FindNotify */ } diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 2ec99f833142..a57f5d6e6213 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -167,7 +167,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) return -ENOMEM; } - cFYI(1, ("Full path: %s ", full_path)); + cFYI(1, ("Full path: %s", full_path)); cFYI(1, ("symname is %s", symname)); /* BB what if DFS and this volume is on different share? BB */ @@ -186,8 +186,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) inode->i_sb,xid); if (rc != 0) { - cFYI(1, - ("Create symlink worked but get_inode_info failed with rc = %d ", + cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d", rc)); } else { if (pTcon->nocase) @@ -289,7 +288,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) else { cFYI(1,("num referral: %d",num_referrals)); if(referrals) { - cFYI(1,("referral string: %s ",referrals)); + cFYI(1,("referral string: %s",referrals)); strncpy(tmpbuffer, referrals, len-1); } } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index b689c5035124..6b36c43d38f5 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -909,7 +909,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) case 1: if (filldir(direntry, "..", 2, file->f_pos, file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { - cERROR(1, ("Filldir for parent dir failed ")); + cERROR(1, ("Filldir for parent dir failed")); rc = -ENOMEM; break; } diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 3da80409466c..17ba329e2b3d 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -654,8 +654,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { up(&ses->server->tcpSem); - cERROR(1, - ("Illegal length, greater than maximum frame, %d ", + cERROR(1, ("Illegal length, greater than maximum frame, %d", in_buf->smb_buf_length)); DeleteMidQEntry(midQ); /* If not lock req, update # of requests on wire to server */ From 3979877e5606ecc58c5a31bd0078c6d80ba9cbe7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 31 May 2006 22:40:51 +0000 Subject: [PATCH 002/556] [CIFS] Support for setting up SMB sessions to legacy lanman servers --- fs/Kconfig | 40 +++- fs/cifs/CHANGES | 5 + fs/cifs/Makefile | 2 +- fs/cifs/cifs_debug.c | 84 +++++-- fs/cifs/cifs_debug.h | 4 + fs/cifs/cifs_unicode.c | 1 + fs/cifs/cifsencrypt.c | 2 + fs/cifs/cifsfs.c | 4 +- fs/cifs/cifsglob.h | 49 ++-- fs/cifs/cifspdu.h | 37 ++- fs/cifs/cifsproto.h | 2 +- fs/cifs/cifssmb.c | 95 +++++++- fs/cifs/connect.c | 39 ++-- fs/cifs/dir.c | 2 +- fs/cifs/fcntl.c | 4 +- fs/cifs/inode.c | 3 +- fs/cifs/misc.c | 10 +- fs/cifs/readdir.c | 16 +- fs/cifs/sess.c | 511 +++++++++++++++++++++++++++++++++++++++++ fs/cifs/smbencrypt.c | 1 + 20 files changed, 836 insertions(+), 75 deletions(-) create mode 100644 fs/cifs/sess.c diff --git a/fs/Kconfig b/fs/Kconfig index f9b5842c8d2d..c4eaacb86071 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1663,7 +1663,7 @@ config CIFS_STATS mounted by the cifs client to be displayed in /proc/fs/cifs/Stats config CIFS_STATS2 - bool "CIFS extended statistics" + bool "Extended statistics" depends on CIFS_STATS help Enabling this option will allow more detailed statistics on SMB @@ -1676,6 +1676,32 @@ config CIFS_STATS2 Unless you are a developer or are doing network performance analysis or tuning, say N. +config CIFS_WEAK_PW_HASH + bool "Support legacy servers which use weaker LANMAN security" + depends on CIFS + help + Modern CIFS servers including Samba and most Windows versions + (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos) + security mechanisms. These hash the password more securely + than the mechanisms used in the older LANMAN version of the + SMB protocol needed to establish sessions with old SMB servers. + + Enabling this option allows the cifs module to mount to older + LANMAN based servers such as OS/2 and Windows 95, but such + mounts may be less secure than mounts using NTLM or more recent + security mechanisms if you are on a public network. Unless you + have a need to access old SMB servers (and are on a private + network) you probably want to say N. Even if this support + is enabled in the kernel build, they will not be used + automatically. At runtime LANMAN mounts are disabled but + can be set to required (or optional) either in + /proc/fs/cifs (see fs/cifs/README for more detail) or via an + option on the mount command. This support is disabled by + default in order to reduce the possibility of a downgrade + attack. + + If unsure, say N. + config CIFS_XATTR bool "CIFS extended attributes" depends on CIFS @@ -1704,6 +1730,16 @@ config CIFS_POSIX (such as Samba 3.10 and later) which can negotiate CIFS POSIX ACL support. If unsure, say N. +config CIFS_DEBUG2 + bool "Enable additional CIFS debugging routines + help + Enabling this option adds a few more debugging routines + to the cifs code which slightly increases the size of + the cifs module and can cause additional logging of debug + messages in some error paths, slowing performance. This + option can be turned off unless you are debugging + cifs problems. If unsure, say N. + config CIFS_EXPERIMENTAL bool "CIFS Experimental Features (EXPERIMENTAL)" depends on CIFS && EXPERIMENTAL @@ -1719,7 +1755,7 @@ config CIFS_EXPERIMENTAL If unsure, say N. config CIFS_UPCALL - bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" + bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" depends on CIFS_EXPERIMENTAL select CONNECTOR help diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 953d2f7f88b0..b878dfcff0f0 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,8 @@ +Version 1.44 +------------ +Rewritten sessionsetup support, including support for legacy SMB +session setup needed for OS/2 and older servers such as Windows 95 and 98. + Version 1.43 ------------ POSIX locking to servers which support CIFS POSIX Extensions diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 58c77254a23b..a26f26ed5a17 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 ntlmssp.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 diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index f4124a32bef8..7f4013a8607f 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -39,7 +39,7 @@ cifs_dump_mem(char *label, void *data, int length) char *charptr = data; char buf[10], line[80]; - printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n", + printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n", label, length, data); for (i = 0; i < length; i += 16) { line[0] = 0; @@ -57,6 +57,57 @@ cifs_dump_mem(char *label, void *data, int length) } } +#ifdef CONFIG_CIFS_DEBUG2 +void cifs_dump_detail(struct smb_hdr * smb) +{ + cERROR(1,("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d", + smb->Command, smb->Status.CifsError, + smb->Flags, smb->Flags2, smb->Mid, smb->Pid)); + cERROR(1,("smb buf %p len %d", smb, smbCalcSize_LE(smb))); +} + + +void cifs_dump_mids(struct TCP_Server_Info * server) +{ + struct list_head *tmp; + struct mid_q_entry * mid_entry; + + if(server == NULL) + return; + + cERROR(1,("Dump pending requests:")); + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct mid_q_entry, qhead); + if(mid_entry) { + cERROR(1,("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", + mid_entry->midState, + (int)mid_entry->command, + mid_entry->pid, + mid_entry->tsk, + mid_entry->mid)); +#ifdef CONFIG_CIFS_STATS2 + cERROR(1,("IsLarge: %d buf: %p time rcv: %ld now: %ld", + mid_entry->largeBuf, + mid_entry->resp_buf, + mid_entry->when_received, + jiffies)); +#endif /* STATS2 */ + cERROR(1,("IsMult: %d IsEnd: %d", mid_entry->multiRsp, + mid_entry->multiEnd)); + if(mid_entry->resp_buf) { + cifs_dump_detail(mid_entry->resp_buf); + cifs_dump_mem("existing buf: ", + mid_entry->resp_buf, + 62 /* fixme */); + } + + } + } + spin_unlock(&GlobalMid_Lock); +} +#endif /* CONFIG_CIFS_DEBUG2 */ + #ifdef CONFIG_PROC_FS static int cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, @@ -73,7 +124,6 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, *beginBuffer = buf + offset; - length = sprintf(buf, "Display Internal CIFS Data Structures for Debugging\n" @@ -397,10 +447,10 @@ static read_proc_t multiuser_mount_read; static write_proc_t multiuser_mount_write; static read_proc_t extended_security_read; static write_proc_t extended_security_write; -static read_proc_t ntlmv2_enabled_read; +/* static read_proc_t ntlmv2_enabled_read; static write_proc_t ntlmv2_enabled_write; static read_proc_t packet_signing_enabled_read; -static write_proc_t packet_signing_enabled_write; +static write_proc_t packet_signing_enabled_write;*/ static read_proc_t experimEnabled_read; static write_proc_t experimEnabled_write; static read_proc_t linuxExtensionsEnabled_read; @@ -469,7 +519,7 @@ cifs_proc_init(void) if (pde) pde->write_proc = lookupFlag_write; - pde = +/* pde = create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, ntlmv2_enabled_read, NULL); if (pde) @@ -479,7 +529,7 @@ cifs_proc_init(void) create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, packet_signing_enabled_read, NULL); if (pde) - pde->write_proc = packet_signing_enabled_write; + pde->write_proc = packet_signing_enabled_write;*/ } void @@ -496,9 +546,9 @@ cifs_proc_clean(void) #endif remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("OplockEnabled", proc_fs_cifs); - remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); +/* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */ remove_proc_entry("ExtendedSecurity",proc_fs_cifs); - remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); +/* remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */ remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); remove_proc_entry("Experimental",proc_fs_cifs); remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); @@ -787,7 +837,7 @@ extended_security_read(char *page, char **start, off_t off, { int len; - len = sprintf(page, "%d\n", extended_security); + len = sprintf(page, "0x%x\n", extended_security); len -= off; *start = page + off; @@ -808,19 +858,25 @@ extended_security_write(struct file *file, const char __user *buffer, { char c; int rc; + cERROR(1,("size %ld",count)); /* BB removeme BB */ + if((count < 2) || (count > 8)) + return -EINVAL; rc = get_user(c, buffer); + +/* BB fixme need to parse more characters in order to handle CIFSSEC flags */ + if (rc) return rc; if (c == '0' || c == 'n' || c == 'N') - extended_security = 0; + extended_security = CIFSSEC_DEF; /* default */ else if (c == '1' || c == 'y' || c == 'Y') - extended_security = 1; + extended_security = CIFSSEC_MAX; return count; } -static int +/* static int ntlmv2_enabled_read(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -855,6 +911,8 @@ ntlmv2_enabled_write(struct file *file, const char __user *buffer, ntlmv2_support = 0; else if (c == '1' || c == 'y' || c == 'Y') ntlmv2_support = 1; + else if (c == '2') + ntlmv2_support = 2; return count; } @@ -898,7 +956,7 @@ packet_signing_enabled_write(struct file *file, const char __user *buffer, sign_CIFS_PDUs = 2; return count; -} +} */ #endif diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h index 4304d9dcfb6c..c26cd0d2c6d5 100644 --- a/fs/cifs/cifs_debug.h +++ b/fs/cifs/cifs_debug.h @@ -24,6 +24,10 @@ #define _H_CIFS_DEBUG void cifs_dump_mem(char *label, void *data, int length); +#ifdef CONFIG_CIFS_DEBUG2 +void cifs_dump_detail(struct smb_hdr *); +void cifs_dump_mids(struct TCP_Server_Info *); +#endif extern int traceSMB; /* flag which enables the function below */ void dump_smb(struct smb_hdr *, int); #define CIFS_INFO 0x01 diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index d2b128255944..d2a8b2941fc2 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -22,6 +22,7 @@ #include "cifs_unicode.h" #include "cifs_uniupr.h" #include "cifspdu.h" +#include "cifsglob.h" #include "cifs_debug.h" /* diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index e7d63737e651..08781a4698b4 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -225,6 +225,8 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ user_name_len = strlen(ses->userName); if(user_name_len > MAX_USERNAME_SIZE) return -EINVAL; + if(ses->domainName == NULL) + return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ dom_name_len = strlen(ses->domainName); if(dom_name_len > MAX_USERNAME_SIZE) return -EINVAL; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c262d8874ce9..700570522b23 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -56,8 +56,8 @@ unsigned int experimEnabled = 0; unsigned int linuxExtEnabled = 1; unsigned int lookupCacheEnabled = 1; unsigned int multiuser_mount = 0; -unsigned int extended_security = 0; -unsigned int ntlmv2_support = 0; +unsigned int extended_security = CIFSSEC_DEF; +/* unsigned int ntlmv2_support = 0; */ unsigned int sign_CIFS_PDUs = 1; extern struct task_struct * oplockThread; /* remove sparse warning */ struct task_struct * oplockThread = NULL; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 006eb33bff5f..7a042041a16a 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -88,7 +88,8 @@ enum statusEnum { }; enum securityEnum { - NTLM = 0, /* Legacy NTLM012 auth with NTLM hash */ + LANMAN = 0, /* Legacy LANMAN auth */ + NTLM, /* Legacy NTLM012 auth with NTLM hash */ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ RawNTLMSSP, /* NTLMSSP without SPNEGO */ NTLMSSP, /* NTLMSSP via SPNEGO */ @@ -179,7 +180,9 @@ struct cifsUidInfo { struct cifsSesInfo { struct list_head cifsSessionList; struct semaphore sesSem; +#if 0 struct cifsUidInfo *uidInfo; /* pointer to user info */ +#endif struct TCP_Server_Info *server; /* pointer to server info */ atomic_t inUse; /* # of mounts (tree connections) on this ses */ enum statusEnum status; @@ -194,7 +197,7 @@ struct cifsSesInfo { char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for TCP names - will ipv6 and sctp addresses fit? */ char userName[MAX_USERNAME_SIZE + 1]; - char domainName[MAX_USERNAME_SIZE + 1]; + char * domainName; char * password; }; /* session flags */ @@ -391,9 +394,9 @@ struct mid_q_entry { struct smb_hdr *resp_buf; /* response buffer */ int midState; /* wish this were enum but can not pass to wait_event */ __u8 command; /* smb command code */ - unsigned multiPart:1; /* multiple responses to one SMB request */ unsigned largeBuf:1; /* if valid response, is pointer to large buf */ - unsigned multiResp:1; /* multiple trans2 responses for one request */ + unsigned multiRsp:1; /* multiple trans2 responses for one request */ + unsigned multiEnd:1; /* both received */ }; struct oplock_q_entry { @@ -430,15 +433,35 @@ struct dir_notify_req { #define CIFS_LARGE_BUFFER 2 #define CIFS_IOVEC 4 /* array of response buffers */ -/* Type of session setup needed */ -#define CIFS_PLAINTEXT 0 -#define CIFS_LANMAN 1 -#define CIFS_NTLM 2 -#define CIFS_NTLMSSP_NEG 3 -#define CIFS_NTLMSSP_AUTH 4 -#define CIFS_SPNEGO_INIT 5 -#define CIFS_SPNEGO_TARG 6 +/* Security Flags: indicate type of session setup needed */ +#define CIFSSEC_MAY_SIGN 0x00001 +#define CIFSSEC_MAY_NTLM 0x00002 +#define CIFSSEC_MAY_NTLMV2 0x00004 +#define CIFSSEC_MAY_KRB5 0x00008 +#ifdef CONFIG_CIFS_WEAK_PW_HASH +#define CIFSSEC_MAY_LANMAN 0x00010 +#define CIFSSEC_MAY_PLNTXT 0x00020 +#endif /* weak passwords */ +#define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ +#define CIFSSEC_MUST_SIGN 0x01001 +/* note that only one of the following can be set so the +result of setting MUST flags more than once will be to +require use of the stronger protocol */ +#define CIFSSEC_MUST_NTLM 0x02002 +#define CIFSSEC_MUST_NTLMV2 0x04004 +#define CIFSSEC_MUST_KRB5 0x08008 +#ifdef CONFIG_CIFS_WEAK_PW_HASH +#define CIFSSEC_MUST_LANMAN 0x10010 +#define CIFSSEC_MUST_PLNTXT 0x20020 +#define CIFSSEC_MASK 0x37037 /* current flags supported if weak */ +#else +#define CIFSSEC_MASK 0x07007 /* flags supported if no weak config */ +#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 /* ***************************************************************** * All constants go here @@ -540,8 +563,8 @@ GLOBAL_EXTERN unsigned int experimEnabled; GLOBAL_EXTERN unsigned int lookupCacheEnabled; GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent with more secure ntlmssp2 challenge/resp */ -GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ +GLOBAL_EXTERN unsigned int secFlags; GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index b2233ac05bd2..e0ff9b56cc4c 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _CIFSPDU_H @@ -24,8 +24,14 @@ #include +#ifdef CONFIG_CIFS_WEAK_PW_HASH +#define LANMAN_PROT 0 +#define CIFS_PROT 1 +#else #define CIFS_PROT 0 -#define BAD_PROT CIFS_PROT+1 +#endif +#define POSIX_PROT CIFS_PROT+1 +#define BAD_PROT 0xFFFF /* SMB command codes */ /* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses @@ -400,6 +406,25 @@ typedef struct negotiate_req { unsigned char DialectsArray[1]; } __attribute__((packed)) NEGOTIATE_REQ; +/* Dialect index is 13 for LANMAN */ + +typedef struct lanman_neg_rsp { + struct smb_hdr hdr; /* wct = 13 */ + __le16 DialectIndex; + __le16 SecurityMode; + __le16 MaxBufSize; + __le16 MaxMpxCount; + __le16 MaxNumberVcs; + __le16 RawMode; + __le32 SessionKey; + __le32 ServerTime; + __le16 ServerTimeZone; + __le16 EncryptionKeyLength; + __le16 Reserved; + __u16 ByteCount; + unsigned char EncryptionKey[1]; +} __attribute__((packed)) LANMAN_NEG_RSP; + typedef struct negotiate_rsp { struct smb_hdr hdr; /* wct = 17 */ __le16 DialectIndex; @@ -520,8 +545,8 @@ typedef union smb_com_session_setup_andx { __le16 MaxMpxCount; __le16 VcNumber; __u32 SessionKey; - __le16 PassswordLength; - __u32 Reserved; + __le16 PasswordLength; + __u32 Reserved; /* encrypt key len and offset */ __le16 ByteCount; unsigned char AccountPassword[1]; /* followed by */ /* STRING AccountName */ @@ -1844,13 +1869,13 @@ typedef struct { typedef struct { __le32 DeviceType; __le32 DeviceCharacteristics; -} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ +} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */ typedef struct { __le32 Attributes; __le32 MaxPathNameComponentLength; __le32 FileSystemNameLen; - char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ + char FileSystemName[52]; /* do not have to save this - get subset? */ } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO; /******************************************************************************/ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 310ea2f0e0bf..ff78cf7b0d1b 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -69,7 +69,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct, struct cifsSesInfo *ses, void ** request_buf); extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, - const int stage, int * pNTLMv2_flg, + const int stage, const struct nls_table *nls_cp); #endif extern __u16 GetNextMid(struct TCP_Server_Info *server); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f00369277c06..da3154fa9c8a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -44,8 +44,11 @@ static struct { int index; char *name; } protocols[] = { +#ifdef CONFIG_CIFS_WEAK_PW_HASH + {LANMAN_PROT, "\2LM1.2X002"}, +#endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, - {CIFS_PROT, "\2POSIX 2"}, + {POSIX_PROT, "\2POSIX 2"}, {BAD_PROT, "\2"} }; #else @@ -53,11 +56,29 @@ static struct { int index; char *name; } protocols[] = { +#ifdef CONFIG_CIFS_WEAK_PW_HASH + {LANMAN_PROT, "\2LM1.2X002"}, +#endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, {BAD_PROT, "\2"} }; #endif +/* define the number of elements in the cifs dialect array */ +#ifdef CONFIG_CIFS_POSIX +#ifdef CONFIG_CIFS_WEAK_PW_HASH +#define CIFS_NUM_PROT 3 +#else +#define CIFS_NUM_PROT 2 +#endif /* CIFS_WEAK_PW_HASH */ +#else /* not posix */ +#ifdef CONFIG_CIFS_WEAK_PW_HASH +#define CIFS_NUM_PROT 2 +#else +#define CIFS_NUM_PROT 1 +#endif /* CONFIG_CIFS_WEAK_PW_HASH */ +#endif /* CIFS_POSIX */ + /* Mark as invalid, all open files on tree connections since they were closed when session to server was lost */ @@ -322,7 +343,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, /* potential retries of smb operations it turns out we can determine */ /* from the mid flags when the request buffer can be resent without */ /* having to use a second distinct buffer for the response */ - *response_buf = *request_buf; + if(response_buf) + *response_buf = *request_buf; header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, wct /*wct */ ); @@ -373,6 +395,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) NEGOTIATE_RSP *pSMBr; int rc = 0; int bytes_returned; + int i; struct TCP_Server_Info * server; u16 count; @@ -388,19 +411,71 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) return rc; pSMB->hdr.Mid = GetNextMid(server); pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; - if (extended_security) - pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - - count = strlen(protocols[0].name) + 1; - strncpy(pSMB->DialectsArray, protocols[0].name, 30); - /* null guaranteed to be at end of source and target buffers anyway */ - +/* if (extended_security) + pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/ + + count = 0; + for(i=0;iDialectsArray+count, protocols[i].name, 16); + count += strlen(protocols[i].name) + 1; + /* null at end of source and target buffers anyway */ + } pSMB->hdr.smb_buf_length += count; pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc == 0) { + cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); + /* Check wct = 1 error case */ + if((pSMBr->hdr.WordCount < 13) + || (pSMBr->DialectIndex == BAD_PROT)) { + /* core returns wct = 1, but we do not ask for + core - otherwise it just comes when dialect + index is -1 indicating we could not negotiate + a common dialect */ + rc = -EOPNOTSUPP; + goto neg_err_exit; + } else if((pSMBr->hdr.WordCount == 13) && + (pSMBr->DialectIndex == LANMAN_PROT)) { + struct lanman_neg_rsp * rsp = + (struct lanman_neg_rsp *)pSMBr; + + + /* BB Mark ses struct as negotiated lanman level BB */ + server->secType = LANMAN; + server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); + server->maxReq = le16_to_cpu(rsp->MaxMpxCount); + server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), + (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); + + /* BB what do we do with raw mode? BB */ + server->timeZone = le16_to_cpu(rsp->ServerTimeZone); + /* Do we have to set signing flags? no signing + was available LANMAN - default should be ok */ + + /* BB FIXME set default dummy capabilities since + they are not returned by the server in this dialect */ + + /* get server time for time conversions and add + code to use it and timezone since this is not UTC */ + + if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { + memcpy(server->cryptKey, rsp->EncryptionKey, + CIFS_CRYPTO_KEY_SIZE); + } else { + rc = -EIO; + goto neg_err_exit; + } + + cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ + goto neg_err_exit; + } else if(pSMBr->hdr.WordCount != 17) { + /* unknown wct */ + rc = -EOPNOTSUPP; + goto neg_err_exit; + } + server->secMode = pSMBr->SecurityMode; if((server->secMode & SECMODE_USER) == 0) cFYI(1,("share mode security")); @@ -479,7 +554,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) } } - +neg_err_exit: cifs_buf_release(pSMB); return rc; } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index bae1479318d1..7ffb8f244f6a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -49,8 +49,6 @@ static DECLARE_COMPLETION(cifsd_complete); -extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, - unsigned char *p24); extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); @@ -585,9 +583,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) /* merge response - fix up 1st*/ if(coalesce_t2(smb_buffer, mid_entry->resp_buf)) { + mid_entry->multiRsp = 1; break; } else { /* all parts received */ + mid_entry->multiEnd = 1; goto multi_t2_fnd; } } else { @@ -632,9 +632,14 @@ multi_t2_fnd: wake_up_process(task_to_wake); } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE) && (isMultiRsp == FALSE)) { - cERROR(1, ("No task to wake, unknown frame rcvd!")); + cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter)); cifs_dump_mem("Received Data is: ",(char *)smb_buffer, sizeof(struct smb_hdr)); +#ifdef CONFIG_CIFS_DEBUG2 + cifs_dump_detail(smb_buffer); + cifs_dump_mids(server); +#endif /* CIFS_DEBUG2 */ + } } /* end while !EXITING */ @@ -976,7 +981,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) } /* BB are there cases in which a comma can be valid in a domain name and need special handling? */ - if (strnlen(value, 65) < 65) { + if (strnlen(value, 256) < 256) { vol->domainname = value; cFYI(1, ("Domain name set")); } else { @@ -1762,9 +1767,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (volume_info.username) strncpy(pSesInfo->userName, volume_info.username,MAX_USERNAME_SIZE); - if (volume_info.domainname) - strncpy(pSesInfo->domainName, - volume_info.domainname,MAX_USERNAME_SIZE); + if (volume_info.domainname) { + int len = strlen(volume_info.domainname); + pSesInfo->domainName = + kmalloc(len + 1, GFP_KERNEL); + if(pSesInfo->domainName) + strcpy(pSesInfo->domainName, + volume_info.domainname); + } pSesInfo->linux_uid = volume_info.linux_uid; down(&pSesInfo->sesSem); rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); @@ -2054,7 +2064,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; } if(user == NULL) - bytes_returned = 0; /* skill null user */ + bytes_returned = 0; /* skip null user */ else bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, @@ -2635,8 +2645,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; if(sign_CIFS_PDUs) negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; - if(ntlmv2_support) - negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; +/* if(ntlmv2_support) + negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/ /* setup pointers to domain name and workstation name */ bcc_ptr += SecurityBlobLength; @@ -3429,7 +3439,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, } /* else do not bother copying these informational fields */ } - tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); + if(smb_buffer_response->WordCount == 3) + tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); + else + tcon->Flags = 0; cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags)); } else if ((rc == 0) && tcon == NULL) { /* all we need to save for IPC$ connection */ @@ -3528,8 +3541,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, pSesInfo->server->timeZone)); #ifdef CONFIG_CIFS_EXPERIMENTAL if(experimEnabled > 1) - rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */, - &ntlmv2_flag, nls_info); + rc = CIFS_SessSetup(xid, pSesInfo, + first_time, nls_info); else #endif if (extended_security diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 57bdf7f734bf..e6ed64e94b7b 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -113,7 +113,7 @@ cifs_bp_rename_retry: full_path[namelen+2] = 0; BB remove above eight lines BB */ -/* Inode operations in similar order to how they appear in the Linux file fs.h */ +/* Inode operations in similar order to how they appear in Linux file fs.h */ int cifs_create(struct inode *inode, struct dentry *direntry, int mode, diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 633a93811328..d91a3d44e9e3 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c @@ -91,14 +91,14 @@ int cifs_dir_notify(struct file * file, unsigned long arg) if(full_path == NULL) { rc = -ENOMEM; } else { - cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */ + cFYI(1,("dir notify on file %s Arg 0x%lx",full_path,arg)); rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ | SYNCHRONIZE, 0 /* create options */, &netfid, &oplock,NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); /* BB fixme - add this handle to a notify handle list */ if(rc) { - cERROR(1,("Could not open directory for notify")); /* BB remove BB */ + cFYI(1,("Could not open directory for notify")); } else { filter = convert_to_cifs_notify_flags(arg); if(filter != 0) { diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 77a9e2f912fd..a609d2668032 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1121,7 +1121,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) xid = GetXid(); - cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x", + cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", direntry->d_name.name, attrs->ia_valid)); cifs_sb = CIFS_SB(direntry->d_inode->i_sb); @@ -1157,6 +1157,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) when the local oplock break takes longer to flush writebehind data than the SMB timeout for the SetPathInfo request would allow */ + open_file = find_writable_file(cifsInode); if (open_file) { __u16 nfid = open_file->netfid; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index fafd056426e4..22c937e5884f 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -101,6 +101,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free) kfree(buf_to_free->serverDomain); kfree(buf_to_free->serverNOS); kfree(buf_to_free->password); + kfree(buf_to_free->domainName); kfree(buf_to_free); } @@ -499,11 +500,12 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) if(pSMBr->ByteCount > sizeof(struct file_notify_information)) { data_offset = le32_to_cpu(pSMBr->DataOffset); - pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol - + data_offset); - cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName, + pnotify = (struct file_notify_information *) + ((char *)&pSMBr->hdr.Protocol + data_offset); + cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName, pnotify->Action)); /* BB removeme BB */ - /* cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */ + /* cifs_dump_mem("Rcvd notify Data: ",buf, + sizeof(struct smb_hdr)+60); */ return TRUE; } if(pSMBr->hdr.Status.CifsError) { diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 6b36c43d38f5..53903a27f786 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -31,8 +31,8 @@ #include "cifs_fs_sb.h" #include "cifsfs.h" -/* BB fixme - add debug wrappers around this function to disable it fixme BB */ -/* static void dump_cifs_file_struct(struct file *file, char *label) +#ifdef CONFIG_CIFS_DEBUG2 +static void dump_cifs_file_struct(struct file *file, char *label) { struct cifsFileInfo * cf; @@ -53,7 +53,8 @@ } } -} */ +} +#endif /* DEBUG2 */ /* Returns one if new inode created (which therefore needs to be hashed) */ /* Might check in the future if inode number changed so we can rehash inode */ @@ -597,7 +598,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, . and .. for the root of a drive and for those we need to start two entries earlier */ -/* dump_cifs_file_struct(file, "In fce ");*/ +#ifdef CONFIG_CIFS_DEBUG2 + dump_cifs_file_struct(file, "In fce "); +#endif if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) { @@ -980,9 +983,10 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) rc = cifs_filldir(current_entry, file, filldir, direntry,tmp_buf); file->f_pos++; - if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) { + if(file->f_pos == + cifsFile->srch_inf.index_of_last_entry) { cFYI(1,("last entry in buf at pos %lld %s", - file->f_pos,tmp_buf)); /* BB removeme BB */ + file->f_pos,tmp_buf)); cifs_save_resume_key(current_entry,cifsFile); break; } else diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c new file mode 100644 index 000000000000..34998416eb73 --- /dev/null +++ b/fs/cifs/sess.c @@ -0,0 +1,511 @@ +/* + * fs/cifs/sess.c + * + * SMB/CIFS session setup handling routines + * + * Copyright (c) International Business Machines Corp., 2006 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * 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 "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_unicode.h" +#include "cifs_debug.h" +#include "ntlmssp.h" +#include "nterr.h" +#include + +extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, + unsigned char *p24); + +extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, + unsigned char *p24); + +#ifdef CONFIG_CIFS_EXPERIMENTAL + +static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) +{ + __u32 capabilities = 0; + + /* init fields common to all four types of SessSetup */ + /* note that header is initialized to zero in header_assemble */ + pSMB->req.AndXCommand = 0xFF; + pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); + pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); + + /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */ + + /* BB verify whether signing required on neg or just on auth frame + (and NTLM case) */ + + capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | + CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + if (ses->capabilities & CAP_UNICODE) { + pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE; + capabilities |= CAP_UNICODE; + } + if (ses->capabilities & CAP_STATUS32) { + pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS; + capabilities |= CAP_STATUS32; + } + if (ses->capabilities & CAP_DFS) { + pSMB->req.hdr.Flags2 |= SMBFLG2_DFS; + capabilities |= CAP_DFS; + } + if (ses->capabilities & CAP_UNIX) { + capabilities |= CAP_UNIX; + } + + /* BB check whether to init vcnum BB */ + return capabilities; +} + +void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, + const struct nls_table * nls_cp) +{ + char * bcc_ptr = *pbcc_area; + int bytes_ret = 0; + + /* BB FIXME add check that strings total less + than 335 or will need to send them as arrays */ + + /* align unicode strings, must be word aligned */ + if ((long) bcc_ptr % 2) { + *bcc_ptr = 0; + bcc_ptr++; + } + /* copy user */ + if(ses->userName == NULL) { + /* BB what about null user mounts - check that we do this BB */ + } else { /* 300 should be long enough for any conceivable user name */ + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName, + 300, nls_cp); + } + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* account for null termination */ + /* copy domain */ + if(ses->domainName == NULL) + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, + "CIFS_LINUX_DOM", 32, nls_cp); + 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, system_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; +} + +void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, + const struct nls_table * nls_cp) +{ + char * bcc_ptr = *pbcc_area; + + /* copy user */ + /* BB what about null user mounts - check that we do this BB */ + /* copy user */ + if(ses->userName == NULL) { + /* BB what about null user mounts - check that we do this BB */ + } else { /* 300 should be long enough for any conceivable user name */ + strncpy(bcc_ptr, ses->userName, 300); + } + /* BB improve check for overflow */ + bcc_ptr += strnlen(ses->userName, 200); + *bcc_ptr = 0; + bcc_ptr++; /* account for null termination */ + + /* copy domain */ + + if(ses->domainName == NULL) { + strcpy(bcc_ptr, "CIFS_LINUX_DOM"); + bcc_ptr += 14; /* strlen(CIFS_LINUX_DOM) */ + } else { + strncpy(bcc_ptr, ses->domainName, 256); + bcc_ptr += strnlen(ses->domainName, 256); + } + *bcc_ptr = 0; + bcc_ptr++; + + /* BB check for overflow here */ + + strcpy(bcc_ptr, "Linux version "); + bcc_ptr += strlen("Linux version "); + strcpy(bcc_ptr, system_utsname.release); + bcc_ptr += strlen(system_utsname.release) + 1; + + strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); + bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; + + *pbcc_area = bcc_ptr; +} + +int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, + const struct nls_table * nls_cp) +{ + int rc = 0; + int words_left, len; + char * data = *pbcc_area; + + + + cFYI(1,("bleft %d",bleft)); + + + /* word align, if bytes remaining is not even */ + if(bleft % 2) { + bleft--; + data++; + } + words_left = bleft / 2; + + /* save off server operating system */ + len = UniStrnlen((wchar_t *) data, words_left); + +/* 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 */ + if(len >= words_left) + return rc; + + if(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); + } + data += 2 * (len + 1); + words_left -= len + 1; + + /* save off server network operating system */ + len = UniStrnlen((wchar_t *) data, words_left); + + if(len >= words_left) + return rc; + + if(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, + nls_cp); + if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) { + cFYI(1,("NT4 server")); + ses->flags |= CIFS_SES_NT4; + } + } + data += 2 * (len + 1); + words_left -= len + 1; + + /* save off server domain */ + len = UniStrnlen((wchar_t *) data, words_left); + + if(len > words_left) + return rc; + + if(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, + nls_cp); + ses->serverDomain[2*len] = 0; + ses->serverDomain[(2*len) + 1] = 0; + } + data += 2 * (len + 1); + words_left -= len + 1; + + cFYI(1,("words left: %d",words_left)); + + return rc; +} + +int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, + const struct nls_table * nls_cp) +{ + int rc = 0; + int len; + char * bcc_ptr = *pbcc_area; + + cFYI(1,("decode sessetup ascii. bleft %d", bleft)); + + len = strnlen(bcc_ptr, bleft); + if(len >= bleft) + return rc; + + if(ses->serverOS) + kfree(ses->serverOS); + + ses->serverOS = kzalloc(len + 1, GFP_KERNEL); + if(ses->serverOS) + strncpy(ses->serverOS, bcc_ptr, len); + + bcc_ptr += len + 1; + bleft -= len + 1; + + len = strnlen(bcc_ptr, bleft); + if(len >= bleft) + return rc; + + if(ses->serverNOS) + kfree(ses->serverNOS); + + ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); + if(ses->serverNOS) + strncpy(ses->serverNOS, bcc_ptr, len); + + bcc_ptr += len + 1; + bleft -= len + 1; + + len = strnlen(bcc_ptr, bleft); + if(len > bleft) + return rc; + + if(ses->serverDomain) + kfree(ses->serverDomain); + + ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); + if(ses->serverOS) + strncpy(ses->serverOS, bcc_ptr, len); + + bcc_ptr += len + 1; + bleft -= len + 1; + + cFYI(1,("ascii: bytes left %d",bleft)); + + return rc; +} + +int +CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, + const struct nls_table *nls_cp) +{ + int rc = 0; + int wct; + int i; + struct smb_hdr *smb_buf; + char *bcc_ptr; + SESSION_SETUP_ANDX *pSMB; + __u32 capabilities; + int count; + int resp_buf_type = 0; + struct kvec iov[1]; + enum securityEnum type; + __u16 action; + int bytes_remaining; + + if(ses == NULL) + return -EINVAL; + + type = ses->server->secType; + if(type == LANMAN) { +#ifndef CONFIG_CIFS_WEAK_PW_HASH + /* LANMAN and plaintext are less secure and off by default. + So we make this explicitly be turned on in kconfig (in the + build) and turned on at runtime (changed from the default) + in proc/fs/cifs or via mount parm. Unfortunately this is + needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ + return -EOPNOTSUPP; +#endif + wct = 10; /* lanman 2 style sessionsetup */ + } else if(type == NTLM) /* NTLMv2 may retry NTLM */ + wct = 13; /* old style NTLM sessionsetup */ + else /* same size for negotiate or auth, NTLMSSP or extended security */ + wct = 12; + + rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, + (void **)&smb_buf); + if(rc) + return rc; + + pSMB = (SESSION_SETUP_ANDX *)smb_buf; + + capabilities = cifs_ssetup_hdr(ses, pSMB); + bcc_ptr = pByteArea(smb_buf); + + if(type == LANMAN) { +#ifdef CONFIG_CIFS_WEAK_PW_HASH + char lnm_session_key[CIFS_SESSION_KEY_SIZE]; + char password_with_pad[CIFS_ENCPWD_SIZE]; + + /* no capabilities flags in old lanman negotiation */ + + pSMB->old_req.PasswordLength = CIFS_SESSION_KEY_SIZE; + /* BB calculate hash with password */ + /* and copy into bcc */ + + memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); + strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); + + /* calculate old style session key */ + /* toupper may be less broken then repeatedly calling + nls_toupper would be, but neither handles multibyte code pages + but the only alternative would be converting to UCS-16 (Unicode) + uppercasing and converting back which is only worth doing if + we knew it were utf8. utf8 code page needs its own + toupper and tolower and strnicmp functions */ + + for(i = 0; i< CIFS_ENCPWD_SIZE; i++) { + password_with_pad[i] = toupper(password_with_pad[i]); + } + + SMBencrypt(password_with_pad, ses->server->cryptKey, + lnm_session_key); + +#ifdef CONFIG_CIFS_DEBUG2 + cifs_dump_mem("cryptkey: ",ses->server->cryptKey, + CIFS_SESSION_KEY_SIZE); +#endif + /* clear password before we return/free memory */ + memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); + memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESSION_KEY_SIZE); + bcc_ptr += CIFS_SESSION_KEY_SIZE; + + /* can not sign if LANMAN negotiated so no need + to calculate signing key? but what if server + changed to do higher than lanman dialect and + we reconnected would we ever calc signing_key? */ + + cERROR(1,("Negotiating LANMAN setting up strings")); + /* Unicode not allowed for LANMAN dialects */ + ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); +#endif + } else if (type == NTLM) { + char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + + pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); + pSMB->req_no_secext.CaseInsensitivePasswordLength = + cpu_to_le16(CIFS_SESSION_KEY_SIZE); + pSMB->req_no_secext.CaseSensitivePasswordLength = + cpu_to_le16(CIFS_SESSION_KEY_SIZE); + + /* calculate session key */ + SMBNTencrypt(ses->password, ses->server->cryptKey, + ntlm_session_key); + + if(first_time) /* should this be moved into common code + with similar ntlmv2 path? */ + cifs_calculate_mac_key( + ses->server->mac_signing_key, + ntlm_session_key, ses->password); + /* copy session key */ + + memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); + bcc_ptr += CIFS_SESSION_KEY_SIZE; + memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); + bcc_ptr += CIFS_SESSION_KEY_SIZE; + if(ses->capabilities & CAP_UNICODE) + unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); + else + ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); + } else /* NTLMSSP or SPNEGO */ { + pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; + capabilities |= CAP_EXTENDED_SECURITY; + pSMB->req.Capabilities = cpu_to_le32(capabilities); + /* BB set password lengths */ + } + + count = (long) bcc_ptr - (long) pByteArea(smb_buf); + smb_buf->smb_buf_length += count; + + /* if we switch to small buffers, count will need to be fewer + than 383 (strings less than 335 bytes) */ + + BCC_LE(smb_buf) = cpu_to_le16(count); + + + /* BB FIXME check for other non ntlm code paths */ + + /* BB check is this too big for a small smb? */ + + iov[0].iov_base = (char *)pSMB; + iov[0].iov_len = smb_buf->smb_buf_length + 4; + + rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0); + /* SMB request buf freed in SendReceive2 */ + + cFYI(1,("ssetup rc from sendrecv2 is %d",rc)); + if(rc) + goto ssetup_exit; + + pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; + smb_buf = (struct smb_hdr *)iov[0].iov_base; + + if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { + rc = -EIO; + cERROR(1,("bad word count %d", smb_buf->WordCount)); + goto ssetup_exit; + } + action = le16_to_cpu(pSMB->resp.Action); + if (action & GUEST_LOGIN) + cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */ + ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ + cFYI(1, ("UID = %d ", ses->Suid)); + /* response can have either 3 or 4 word count - Samba sends 3 */ + /* and lanman response is 3 */ + bytes_remaining = BCC(smb_buf); + bcc_ptr = pByteArea(smb_buf); + + if(smb_buf->WordCount == 4) { + __u16 blob_len; + blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); + bcc_ptr += blob_len; + if(blob_len > bytes_remaining) { + cERROR(1,("bad security blob length %d", blob_len)); + rc = -EINVAL; + goto ssetup_exit; + } + bytes_remaining -= blob_len; + } + + /* BB check if Unicode and decode strings */ + if(smb_buf->Flags2 & SMBFLG2_UNICODE) + rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, + ses, nls_cp); + else + rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp); + +ssetup_exit: + if(resp_buf_type == CIFS_SMALL_BUFFER) { + cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base)); + cifs_small_buf_release(iov[0].iov_base); + } else if(resp_buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(iov[0].iov_base); + + return rc; +} +#endif /* CONFIG_CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 6103bcdfb16d..f518c5e45035 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -30,6 +30,7 @@ #include #include "cifs_unicode.h" #include "cifspdu.h" +#include "cifsglob.h" #include "md5.h" #include "cifs_debug.h" #include "cifsencrypt.h" From 9c53588ec96d85f82e9bf3fb1af7cca31056e940 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 1 Jun 2006 05:09:10 +0000 Subject: [PATCH 003/556] [CIFS] Missing include shows up on some architectures Signed-off-by: Steve French --- fs/cifs/cifsfs.h | 2 +- fs/cifs/ntlmssp.c | 143 ---------------------------------------------- fs/cifs/sess.c | 1 + 3 files changed, 2 insertions(+), 144 deletions(-) delete mode 100644 fs/cifs/ntlmssp.c diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index c98755dca868..2fc6d6527f1e 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -99,5 +99,5 @@ 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, unsigned int command, unsigned long arg); -#define CIFS_VERSION "1.43" +#define CIFS_VERSION "1.44" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/ntlmssp.c b/fs/cifs/ntlmssp.c deleted file mode 100644 index 115359cc7a32..000000000000 --- a/fs/cifs/ntlmssp.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * fs/cifs/ntlmssp.h - * - * Copyright (c) International Business Machines Corp., 2006 - * Author(s): Steve French (sfrench@us.ibm.com) - * - * 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 "cifspdu.h" -#include "cifsglob.h" -#include "cifsproto.h" -#include "cifs_unicode.h" -#include "cifs_debug.h" -#include "ntlmssp.h" -#include "nterr.h" - -#ifdef CONFIG_CIFS_EXPERIMENTAL -static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) -{ - __u32 capabilities = 0; - - /* init fields common to all four types of SessSetup */ - /* note that header is initialized to zero in header_assemble */ - pSMB->req.AndXCommand = 0xFF; - pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); - pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); - - /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */ - - /* BB verify whether signing required on neg or just on auth frame - (and NTLM case) */ - - capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | - CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; - - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - - if (ses->capabilities & CAP_UNICODE) { - pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE; - capabilities |= CAP_UNICODE; - } - if (ses->capabilities & CAP_STATUS32) { - pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS; - capabilities |= CAP_STATUS32; - } - if (ses->capabilities & CAP_DFS) { - pSMB->req.hdr.Flags2 |= SMBFLG2_DFS; - capabilities |= CAP_DFS; - } - - /* BB check whether to init vcnum BB */ - return capabilities; -} -int -CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int type, - int * pNTLMv2_flg, const struct nls_table *nls_cp) -{ - int rc = 0; - int wct; - struct smb_hdr *smb_buffer; - char *bcc_ptr; - SESSION_SETUP_ANDX *pSMB; - __u32 capabilities; - - if(ses == NULL) - return -EINVAL; - - cFYI(1,("SStp type: %d",type)); - if(type < CIFS_NTLM) { -#ifndef CONFIG_CIFS_WEAK_PW_HASH - /* LANMAN and plaintext are less secure and off by default. - So we make this explicitly be turned on in kconfig (in the - build) and turned on at runtime (changed from the default) - in proc/fs/cifs or via mount parm. Unfortunately this is - needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ - return -EOPNOTSUPP; -#endif - wct = 10; /* lanman 2 style sessionsetup */ - } else if(type < CIFS_NTLMSSP_NEG) - wct = 13; /* old style NTLM sessionsetup */ - else /* same size for negotiate or auth, NTLMSSP or extended security */ - wct = 12; - - rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, - (void **)&smb_buffer); - if(rc) - return rc; - - pSMB = (SESSION_SETUP_ANDX *)smb_buffer; - - capabilities = cifs_ssetup_hdr(ses, pSMB); - bcc_ptr = pByteArea(smb_buffer); - if(type > CIFS_NTLM) { - pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; - capabilities |= CAP_EXTENDED_SECURITY; - pSMB->req.Capabilities = cpu_to_le32(capabilities); - /* BB set password lengths */ - } else if(type < CIFS_NTLM) /* lanman */ { - /* no capabilities flags in old lanman negotiation */ - /* pSMB->old_req.PasswordLength = */ /* BB fixme BB */ - } else /* type CIFS_NTLM */ { - pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); - pSMB->req_no_secext.CaseInsensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); - pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); - } - - - /* copy session key */ - - /* if Unicode, align strings to two byte boundary */ - - /* copy user name */ /* BB Do we need to special case null user name? */ - - /* copy domain name */ - - /* copy Linux version */ - - /* copy network operating system name */ - - /* update bcc and smb buffer length */ - -/* rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */ - /* SMB request buf freed in SendReceive2 */ - - return rc; -} -#endif /* CONFIG_CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 34998416eb73..fdc248fffa0a 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -29,6 +29,7 @@ #include "ntlmssp.h" #include "nterr.h" #include +#include extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); From 7c7b25bc8e392aea781324efa771bc191377b876 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 1 Jun 2006 19:20:10 +0000 Subject: [PATCH 004/556] [CIFS] Support for setting up SMB sessions to legacy lanman servers part 2 --- fs/cifs/cifs_debug.c | 4 +- fs/cifs/cifsencrypt.c | 40 ++++++++++++++++-- fs/cifs/cifsglob.h | 2 +- fs/cifs/cifspdu.h | 3 +- fs/cifs/cifsproto.h | 3 ++ fs/cifs/cifssmb.c | 27 +++++++++--- fs/cifs/connect.c | 47 +++++++++++++-------- fs/cifs/netmisc.c | 2 +- fs/cifs/sess.c | 97 +++++++++++++++++++++++-------------------- 9 files changed, 150 insertions(+), 75 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 7f4013a8607f..4e10e21c54fd 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -508,7 +508,7 @@ cifs_proc_init(void) pde->write_proc = multiuser_mount_write; pde = - create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, + create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs, extended_security_read, NULL); if (pde) pde->write_proc = extended_security_write; @@ -547,7 +547,7 @@ cifs_proc_clean(void) remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("OplockEnabled", proc_fs_cifs); /* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */ - remove_proc_entry("ExtendedSecurity",proc_fs_cifs); + remove_proc_entry("SecurityFlags",proc_fs_cifs); /* remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */ remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); remove_proc_entry("Experimental",proc_fs_cifs); diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 08781a4698b4..e11d8c6bb227 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -26,6 +26,7 @@ #include "md5.h" #include "cifs_unicode.h" #include "cifsproto.h" +#include /* Calculate and return the CIFS signature based on the mac key and the smb pdu */ /* the 16 byte signature must be allocated by the caller */ @@ -35,6 +36,8 @@ extern void mdfour(unsigned char *out, unsigned char *in, int n); extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); +extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, + unsigned char *p24); static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature) @@ -45,7 +48,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, return -EINVAL; MD5Init(&context); - MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); MD5Final(signature,&context); return 0; @@ -90,7 +93,7 @@ static int cifs_calc_signature2(const struct kvec * iov, int n_vec, return -EINVAL; MD5Init(&context); - MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); for(i=0;ipassword, CIFS_ENCPWD_SIZE); + + /* calculate old style session key */ + /* calling toupper is less broken than repeatedly + calling nls_toupper would be since that will never + work for UTF8, but neither handles multibyte code pages + but the only alternative would be converting to UCS-16 (Unicode) + (using a routine something like UniStrupr) then + uppercasing and then converting back from Unicode - which + would only worth doing it if we knew it were utf8. Basically + utf8 and other multibyte codepages each need their own strupper + function since a byte at a time will ont work. */ + + for(i = 0; i < CIFS_ENCPWD_SIZE; i++) { + password_with_pad[i] = toupper(password_with_pad[i]); + } + + SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key); + /* clear password before we return/free memory */ + memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); +} +#endif /* CIFS_WEAK_PW_HASH */ + void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) { struct HMACMD5Context context; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 7a042041a16a..975e69a2e1c4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -158,7 +158,7 @@ struct TCP_Server_Info { /* 16th byte of RFC1001 workstation name is always null */ char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; __u32 sequence_number; /* needed for CIFS PDU signature */ - char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; + char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; }; /* diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e0ff9b56cc4c..135941738d9d 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -116,7 +116,8 @@ /* * Size of the session key (crypto key encrypted with the password */ -#define CIFS_SESSION_KEY_SIZE (24) +#define CIFS_SESS_KEY_SIZE (24) +#define V2_SESS_KEY_SIZE (86) /* * Maximum user name length diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index ff78cf7b0d1b..59b037f14511 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -287,6 +287,9 @@ extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); +#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 CIFSSMBCopy(int xid, struct cifsTconInfo *source_tcon, const char *fromName, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index da3154fa9c8a..6b5be6d59f07 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -438,12 +438,19 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) goto neg_err_exit; } else if((pSMBr->hdr.WordCount == 13) && (pSMBr->DialectIndex == LANMAN_PROT)) { +#ifdef CONFIG_CIFS_WEAK_PW_HASH struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; - - /* BB Mark ses struct as negotiated lanman level BB */ - server->secType = LANMAN; + if((extended_security & CIFSSEC_MAY_LANMAN) || + (extended_security & CIFSSEC_MAY_PLNTXT)) + server->secType = LANMAN; + else { + cERROR(1, ("mount failed weak security disabled" + " in /proc/fs/cifs/SecurityFlags")); + rc = -EOPNOTSUPP; + goto neg_err_exit; + } server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); server->maxReq = le16_to_cpu(rsp->MaxMpxCount); server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), @@ -469,6 +476,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) } cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ +#else /* weak security disabled */ + cERROR(1,("mount failed, cifs module not built with " + "CIFS_WEAK_PW_HASH support")); + rc = -EOPNOTSUPP; +#endif /* WEAK_PW_HASH */ goto neg_err_exit; } else if(pSMBr->hdr.WordCount != 17) { /* unknown wct */ @@ -479,8 +491,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->secMode = pSMBr->SecurityMode; if((server->secMode & SECMODE_USER) == 0) cFYI(1,("share mode security")); - server->secType = NTLM; /* BB override default for - NTLMv2 or kerberos v5 */ + + if(extended_security & CIFSSEC_MUST_NTLMV2) + server->secType = NTLMv2; + else + server->secType = NTLM; + /* else krb5 ... */ + /* one byte - no need to convert this or EncryptionKeyLen from little endian */ server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 7ffb8f244f6a..e6f3d2fff6c0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1990,7 +1990,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, static int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char session_key[CIFS_SESSION_KEY_SIZE], + char session_key[CIFS_SESS_KEY_SIZE], const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; @@ -2048,15 +2048,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); pSMB->req_no_secext.CaseInsensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); bcc_ptr = pByteArea(smb_buffer); - memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; - memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; + memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; + memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ @@ -3004,14 +3004,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->LmChallengeResponse.Buffer = 0; SecurityBlob->NtChallengeResponse.Length = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); SecurityBlob->NtChallengeResponse.MaximumLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); - memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); + memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE); SecurityBlob->NtChallengeResponse.Buffer = cpu_to_le32(SecurityBlobLength); - SecurityBlobLength += CIFS_SESSION_KEY_SIZE; - bcc_ptr += CIFS_SESSION_KEY_SIZE; + SecurityBlobLength += CIFS_SESS_KEY_SIZE; + bcc_ptr += CIFS_SESS_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { if (domain == NULL) { @@ -3350,22 +3350,33 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr = &pSMB->Password[0]; if((ses->server->secMode) & SECMODE_USER) { pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ + *bcc_ptr = 0; /* password is null byte */ bcc_ptr++; /* skip password */ + /* already aligned so no need to do it below */ } else { - pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE); + pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); /* BB FIXME add code to fail this if NTLMv2 or Kerberos specified as required (when that support is added to the vfs in the future) as only NTLM or the much - weaker LANMAN (which we do not send) is accepted + weaker LANMAN (which we do not send by default) is accepted by Samba (not sure whether other servers allow NTLMv2 password here) */ +#ifdef CONFIG_CIFS_WEAK_PW_HASH + if((extended_security & CIFSSEC_MAY_LANMAN) && + (ses->server->secType == LANMAN)) + calc_lanman_hash(ses, bcc_ptr); + else +#endif /* CIFS_WEAK_PW_HASH */ SMBNTencrypt(ses->password, ses->server->cryptKey, bcc_ptr); - bcc_ptr += CIFS_SESSION_KEY_SIZE; - *bcc_ptr = 0; - bcc_ptr++; /* align */ + bcc_ptr += CIFS_SESS_KEY_SIZE; + if(ses->capabilities & CAP_UNICODE) { + /* must align unicode strings */ + *bcc_ptr = 0; /* null byte password */ + bcc_ptr++; + } } if(ses->server->secMode & @@ -3507,7 +3518,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info) { int rc = 0; - char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + char ntlm_session_key[CIFS_SESS_KEY_SIZE]; int ntlmv2_flag = FALSE; int first_time = 0; diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 5de74d216fdd..a0bcdd6f4a67 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -84,7 +84,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { static const struct smb_to_posix_error mapping_table_ERRSRV[] = { {ERRerror, -EIO}, - {ERRbadpw, -EPERM}, + {ERRbadpw, -EACCES}, /* was EPERM */ {ERRbadtype, -EREMOTE}, {ERRaccess, -EACCES}, {ERRinvtid, -ENXIO}, diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index fdc248fffa0a..a52aacb3feff 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -28,12 +28,8 @@ #include "cifs_debug.h" #include "ntlmssp.h" #include "nterr.h" -#include #include -extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, - unsigned char *p24); - extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); @@ -80,7 +76,7 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) return capabilities; } -void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, +static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { char * bcc_ptr = *pbcc_area; @@ -130,7 +126,7 @@ void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, *pbcc_area = bcc_ptr; } -void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, +static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { char * bcc_ptr = *pbcc_area; @@ -173,7 +169,7 @@ void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, *pbcc_area = bcc_ptr; } -int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, +static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { int rc = 0; @@ -255,7 +251,7 @@ int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, return rc; } -int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, +static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { int rc = 0; @@ -317,7 +313,6 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, { int rc = 0; int wct; - int i; struct smb_hdr *smb_buf; char *bcc_ptr; SESSION_SETUP_ANDX *pSMB; @@ -343,7 +338,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, return -EOPNOTSUPP; #endif wct = 10; /* lanman 2 style sessionsetup */ - } else if(type == NTLM) /* NTLMv2 may retry NTLM */ + } else if((type == NTLM) || (type == NTLMv2)) /* NTLMv2 may retry NTLM */ wct = 13; /* old style NTLM sessionsetup */ else /* same size for negotiate or auth, NTLMSSP or extended security */ wct = 12; @@ -360,41 +355,22 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, if(type == LANMAN) { #ifdef CONFIG_CIFS_WEAK_PW_HASH - char lnm_session_key[CIFS_SESSION_KEY_SIZE]; - char password_with_pad[CIFS_ENCPWD_SIZE]; + char lnm_session_key[CIFS_SESS_KEY_SIZE]; /* no capabilities flags in old lanman negotiation */ - pSMB->old_req.PasswordLength = CIFS_SESSION_KEY_SIZE; + pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE; /* BB calculate hash with password */ /* and copy into bcc */ - memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); - strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); - - /* calculate old style session key */ - /* toupper may be less broken then repeatedly calling - nls_toupper would be, but neither handles multibyte code pages - but the only alternative would be converting to UCS-16 (Unicode) - uppercasing and converting back which is only worth doing if - we knew it were utf8. utf8 code page needs its own - toupper and tolower and strnicmp functions */ - - for(i = 0; i< CIFS_ENCPWD_SIZE; i++) { - password_with_pad[i] = toupper(password_with_pad[i]); - } - - SMBencrypt(password_with_pad, ses->server->cryptKey, - lnm_session_key); + calc_lanman_hash(ses, lnm_session_key); #ifdef CONFIG_CIFS_DEBUG2 cifs_dump_mem("cryptkey: ",ses->server->cryptKey, - CIFS_SESSION_KEY_SIZE); + CIFS_SESS_KEY_SIZE); #endif - /* clear password before we return/free memory */ - memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); - memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; + memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; /* can not sign if LANMAN negotiated so no need to calculate signing key? but what if server @@ -406,13 +382,13 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); #endif } else if (type == NTLM) { - char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + char ntlm_session_key[CIFS_SESS_KEY_SIZE]; pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); pSMB->req_no_secext.CaseInsensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); /* calculate session key */ SMBNTencrypt(ses->password, ses->server->cryptKey, @@ -420,15 +396,48 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, if(first_time) /* should this be moved into common code with similar ntlmv2 path? */ - cifs_calculate_mac_key( - ses->server->mac_signing_key, + cifs_calculate_mac_key( ses->server->mac_signing_key, ntlm_session_key, ses->password); /* copy session key */ - memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; - memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; + memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; + memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; + if(ses->capabilities & CAP_UNICODE) + unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); + else + ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); + } else if (type == NTLMv2) { + char * v2_sess_key = kmalloc(V2_SESS_KEY_SIZE, GFP_KERNEL); + + if(v2_sess_key == NULL) { + cifs_small_buf_release(smb_buf); + return -ENOMEM; + } + + pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); + + /* LM2 password would be here if we supported it */ + pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; + /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ + + pSMB->req_no_secext.CaseSensitivePasswordLength = + cpu_to_le16(V2_SESS_KEY_SIZE); + + /* calculate session key */ + CalcNTLMv2_response(ses, v2_sess_key); + if(first_time) /* should this be moved into common code + with similar ntlmv2 path? */ + /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, + response BB FIXME, v2_sess_key); */ + + /* copy session key */ + + /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE); + bcc_ptr += LM2_SESS_KEY_SIZE; */ + memcpy(bcc_ptr, (char *)v2_sess_key, V2_SESS_KEY_SIZE); + bcc_ptr += V2_SESS_KEY_SIZE; if(ses->capabilities & CAP_UNICODE) unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); else From 3856a9d443ee24248683c415e535f7a2b0fed0f3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 1 Jun 2006 19:38:46 +0000 Subject: [PATCH 005/556] [CIFS] Fix minor build breaks due to cifs kconfig issues Signed-off-by: Steve French --- fs/Kconfig | 2 +- fs/cifs/cifssmb.c | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/Kconfig b/fs/Kconfig index c4eaacb86071..d49b2a8c0be6 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1731,7 +1731,7 @@ config CIFS_POSIX CIFS POSIX ACL support. If unsure, say N. config CIFS_DEBUG2 - bool "Enable additional CIFS debugging routines + bool "Enable additional CIFS debugging routines" help Enabling this option adds a few more debugging routines to the cifs code which slightly increases the size of diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6b5be6d59f07..eea8967e598e 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -436,9 +436,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) a common dialect */ rc = -EOPNOTSUPP; goto neg_err_exit; - } else if((pSMBr->hdr.WordCount == 13) && - (pSMBr->DialectIndex == LANMAN_PROT)) { -#ifdef CONFIG_CIFS_WEAK_PW_HASH +#ifdef CONFIG_CIFS_WEAK_PW_HASH + } else if((pSMBr->hdr.WordCount == 13) + && (pSMBr->DialectIndex == LANMAN_PROT)) { struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; @@ -477,8 +477,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ #else /* weak security disabled */ - cERROR(1,("mount failed, cifs module not built with " - "CIFS_WEAK_PW_HASH support")); + } else if(pSMBr->hdr.WordCount == 13) + cERROR(1,("mount failed, cifs module not built " + "with CIFS_WEAK_PW_HASH support")); rc = -EOPNOTSUPP; #endif /* WEAK_PW_HASH */ goto neg_err_exit; From 273d81d6ada951ba99f10b755d6f849dbb352730 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Thu, 1 Jun 2006 19:41:23 +0000 Subject: [PATCH 006/556] [CIFS] Do not overwrite aops cifs should not be overwriting an element of the aops structure, since the structure is shared by all cifs inodes. Instead define a separate aops structure to suit each purpose. I also took the liberty of replacing a hard-coded 4096 with PAGE_CACHE_SIZE Signed-off-by: Dave Kleikamp Signed-off-by: Steven French Signed-off-by: Andrew Morton --- fs/cifs/cifsfs.h | 1 + fs/cifs/file.c | 16 ++++++++++++++++ fs/cifs/inode.c | 14 ++++++++------ fs/cifs/readdir.c | 16 ++++++++++------ 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 2fc6d6527f1e..3011df988bd5 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -33,6 +33,7 @@ #endif extern struct address_space_operations cifs_addr_ops; +extern struct address_space_operations cifs_addr_ops_smallbuf; /* Functions related to super block operations */ extern struct super_operations cifs_super_ops; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 379369ecda96..d62e29fe91f2 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1959,3 +1959,19 @@ struct address_space_operations cifs_addr_ops = { /* .sync_page = cifs_sync_page, */ /* .direct_IO = */ }; + +/* + * cifs_readpages requires the server to support a buffer large enough to + * contain the header plus one complete page of data. Otherwise, we need + * to leave cifs_readpages out of the address space operations. + */ +struct address_space_operations cifs_addr_ops_smallbuf = { + .readpage = cifs_readpage, + .writepage = cifs_writepage, + .writepages = cifs_writepages, + .prepare_write = cifs_prepare_write, + .commit_write = cifs_commit_write, + .set_page_dirty = __set_page_dirty_nobuffers, + /* .sync_page = cifs_sync_page, */ + /* .direct_IO = */ +}; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a609d2668032..b88147c1dc27 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -180,11 +180,12 @@ int cifs_get_inode_info_unix(struct inode **pinode, else /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; - inode->i_data.a_ops = &cifs_addr_ops; /* check if server can support readpages */ if(pTcon->ses->server->maxBuf < - 4096 + MAX_CIFS_HDR_SIZE) - inode->i_data.a_ops->readpages = NULL; + PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) + inode->i_data.a_ops = &cifs_addr_ops_smallbuf; + else + inode->i_data.a_ops = &cifs_addr_ops; } else if (S_ISDIR(inode->i_mode)) { cFYI(1, ("Directory inode")); inode->i_op = &cifs_dir_inode_ops; @@ -519,10 +520,11 @@ int cifs_get_inode_info(struct inode **pinode, else /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; - inode->i_data.a_ops = &cifs_addr_ops; if(pTcon->ses->server->maxBuf < - 4096 + MAX_CIFS_HDR_SIZE) - inode->i_data.a_ops->readpages = NULL; + PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) + inode->i_data.a_ops = &cifs_addr_ops_smallbuf; + else + inode->i_data.a_ops = &cifs_addr_ops; } else if (S_ISDIR(inode->i_mode)) { cFYI(1, ("Directory inode")); inode->i_op = &cifs_dir_inode_ops; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 53903a27f786..e3e762d774df 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -21,6 +21,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include #include #include #include "cifspdu.h" @@ -216,11 +217,13 @@ static void fill_in_inode(struct inode *tmp_inode, else tmp_inode->i_fop = &cifs_file_ops; - tmp_inode->i_data.a_ops = &cifs_addr_ops; if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server->maxBuf < - 4096 + MAX_CIFS_HDR_SIZE)) - tmp_inode->i_data.a_ops->readpages = NULL; + PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) + tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; + else + tmp_inode->i_data.a_ops = &cifs_addr_ops; + if(isNewInode) return; /* No sense invalidating pages for new inode since have not started caching readahead file @@ -339,11 +342,12 @@ static void unix_fill_in_inode(struct inode *tmp_inode, else tmp_inode->i_fop = &cifs_file_ops; - tmp_inode->i_data.a_ops = &cifs_addr_ops; if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server->maxBuf < - 4096 + MAX_CIFS_HDR_SIZE)) - tmp_inode->i_data.a_ops->readpages = NULL; + PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) + tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; + else + tmp_inode->i_data.a_ops = &cifs_addr_ops; if(isNewInode) return; /* No sense invalidating pages for new inode since we From 7a0d22317614ee8e2598feafd4812e33be17f421 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 1 Jun 2006 19:44:37 +0000 Subject: [PATCH 007/556] [CIFS] Missing brace --- fs/cifs/cifssmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index eea8967e598e..b8c236be4d85 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -477,7 +477,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ #else /* weak security disabled */ - } else if(pSMBr->hdr.WordCount == 13) + } else if(pSMBr->hdr.WordCount == 13) { cERROR(1,("mount failed, cifs module not built " "with CIFS_WEAK_PW_HASH support")); rc = -EOPNOTSUPP; From 43411d699e8cf3293674da558d31a02e0012aa9d Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 2 Jun 2006 18:17:11 +0000 Subject: [PATCH 008/556] [CIFS] Fix mapping of old SMB return code Invalid Net Name so it is recognized on mount the old mapping of this was to ENODEV (instead of ENXIO) - but ENODEV is what mount returns when the cifs driver will not load so change this to map to ENXIO (which was what the equivalent condition returned for mapping errors from more modern servers) Signed-off-by: Steve French --- fs/cifs/netmisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index a0bcdd6f4a67..b66eff5dc624 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -88,7 +88,7 @@ static const struct smb_to_posix_error mapping_table_ERRSRV[] = { {ERRbadtype, -EREMOTE}, {ERRaccess, -EACCES}, {ERRinvtid, -ENXIO}, - {ERRinvnetname, -ENODEV}, + {ERRinvnetname, -ENXIO}, {ERRinvdevice, -ENXIO}, {ERRqfull, -ENOSPC}, {ERRqtoobig, -ENOSPC}, From bdc4bf6e8ac8cc29c61c2f0dc61d9776ef9a8ed4 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 2 Jun 2006 22:57:13 +0000 Subject: [PATCH 009/556] [CIFS] Support for older servers which require plaintext passwords disabled by default, but can be enabled via proc for servers which require such support. Also includes support for setting security flags for cifs. See fs/cifs/README Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 56 ++++++++++++++++++++++++++++++------------- fs/cifs/cifsencrypt.c | 9 +++++++ fs/cifs/cifssmb.c | 7 ++++++ 3 files changed, 56 insertions(+), 16 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 4e10e21c54fd..7c0015a96959 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -445,8 +445,8 @@ static read_proc_t traceSMB_read; static write_proc_t traceSMB_write; static read_proc_t multiuser_mount_read; static write_proc_t multiuser_mount_write; -static read_proc_t extended_security_read; -static write_proc_t extended_security_write; +static read_proc_t security_flags_read; +static write_proc_t security_flags_write; /* static read_proc_t ntlmv2_enabled_read; static write_proc_t ntlmv2_enabled_write; static read_proc_t packet_signing_enabled_read; @@ -509,9 +509,9 @@ cifs_proc_init(void) pde = create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs, - extended_security_read, NULL); + security_flags_read, NULL); if (pde) - pde->write_proc = extended_security_write; + pde->write_proc = security_flags_write; pde = create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, @@ -832,7 +832,7 @@ multiuser_mount_write(struct file *file, const char __user *buffer, } static int -extended_security_read(char *page, char **start, off_t off, +security_flags_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len; @@ -853,26 +853,50 @@ extended_security_read(char *page, char **start, off_t off, return len; } static int -extended_security_write(struct file *file, const char __user *buffer, +security_flags_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { + unsigned int flags; + char flags_string[12]; char c; - int rc; + cERROR(1,("size %ld",count)); /* BB removeme BB */ - if((count < 2) || (count > 8)) + + if((count < 1) || (count > 11)) return -EINVAL; - rc = get_user(c, buffer); + memset(flags_string, 0, 12); -/* BB fixme need to parse more characters in order to handle CIFSSEC flags */ + if(copy_from_user(flags_string, buffer, count)) + return -EFAULT; - if (rc) - return rc; - if (c == '0' || c == 'n' || c == 'N') - extended_security = CIFSSEC_DEF; /* default */ - else if (c == '1' || c == 'y' || c == 'Y') - extended_security = CIFSSEC_MAX; + if(count < 3) { + /* single char or single char followed by null */ + c = flags_string[0]; + if (c == '0' || c == 'n' || c == 'N') + extended_security = CIFSSEC_DEF; /* default */ + else if (c == '1' || c == 'y' || c == 'Y') + extended_security = CIFSSEC_MAX; + return count; + } + /* else we have a number */ + flags = simple_strtoul(flags_string, NULL, 0); + + cERROR(1,("sec flags 0x%x", flags)); /* BB FIXME make cFYI */ + + if(flags <= 0) { + cERROR(1,("invalid security flags %s",flags_string)); + return -EINVAL; + } + + if((flags & CIFSSEC_MASK) != CIFSSEC_MASK) { + cERROR(1,("attempt to set unsupported security flags 0x%d", + flags & ~CIFSSEC_MASK)); + return -EINVAL; + } + /* flags look ok - update the global security flags for cifs module */ + extended_security = flags; return count; } diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index e11d8c6bb227..3ae964bbfdc3 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -271,9 +271,18 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) int i; char password_with_pad[CIFS_ENCPWD_SIZE]; + if(ses->server == NULL) + return; + memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); + if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) + if(extended_security & CIFSSEC_MAY_PLNTXT) { + memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); + return; + } + /* calculate old style session key */ /* calling toupper is less broken than repeatedly calling nls_toupper would be since that will never diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b8c236be4d85..77cca3809467 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -492,6 +492,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->secMode = pSMBr->SecurityMode; if((server->secMode & SECMODE_USER) == 0) cFYI(1,("share mode security")); + + if((server->secMode & SECMODE_PW_ENCRYPT) == 0) +#ifdef CONFIG_CIFS_WEAK_PW_HASH + if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) +#endif /* CIFS_WEAK_PW_HASH */ + cERROR(1,("Server requests plain text password" + " but client support disabled")); if(extended_security & CIFSSEC_MUST_NTLMV2) server->secType = NTLMv2; From 254e55ed03e2e8d23089b4a468eec2fd2e1ead9b Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 4 Jun 2006 05:53:15 +0000 Subject: [PATCH 010/556] CIFS] Support for older servers which require plaintext passwords - part 2 Signed-off-by: Steve French --- fs/cifs/README | 32 +++++- fs/cifs/cifsglob.h | 17 ++- fs/cifs/cifspdu.h | 4 + fs/cifs/cifssmb.c | 279 +++++++++++++++++++++++---------------------- fs/cifs/sess.c | 3 +- 5 files changed, 184 insertions(+), 151 deletions(-) diff --git a/fs/cifs/README b/fs/cifs/README index 0355003f4f0a..a68f8e3db2d2 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -485,14 +485,34 @@ PacketSigningEnabled If set to one, cifs packet signing is enabled it. If set to two, cifs packet signing is required even if the server considers packet signing optional. (default 1) +SecurityFlags Flags which control security negotiation and + also packet signing. Authentication (may/must) + flags (e.g. for NTLM and/or NTLMv2) may be combined with + the signing flags. Specifying two different password + hashing mechanisms (as "must use") on the other hand + does not make much sense. Default flags are + 0x07007 + (NTLM, NTLMv2 and packet signing allowed). Maximum + allowable flags if you want to allow mounts to servers + using weaker password hashes is 0x37037 (lanman, + plaintext, ntlm, ntlmv2, signing allowed): + + may use packet signing 0x00001 + must use packet signing 0x01001 + may use NTLM (most common password hash) 0x00002 + must use NTLM 0x02002 + may use NTLMv2 0x00004 + must use NTLMv2 0x04004 + may use Kerberos security (not implemented yet) 0x00008 + must use Kerberos (not implemented yet) 0x08008 + may use lanman (weak) password hash 0x00010 + must use lanman password hash 0x10010 + may use plaintext passwords 0x00020 + must use plaintext passwords 0x20020 + (reserved for future packet encryption) 0x00040 + cifsFYI If set to one, additional debug information is logged to the system error log. (default 0) -ExtendedSecurity If set to one, SPNEGO session establishment - is allowed which enables more advanced - secure CIFS session establishment (default 0) -NTLMV2Enabled If set to one, more secure password hashes - are used when the server supports them and - when kerberos is not negotiated (default 0) traceSMB If set to one, debug information is logged to the system error log with the start of smb requests and responses (default 0) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 975e69a2e1c4..87453a6bcaf8 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -212,12 +212,12 @@ struct cifsTconInfo { struct list_head openFileList; struct semaphore tconSem; struct cifsSesInfo *ses; /* pointer to session associated with */ - char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */ + char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ char *nativeFileSystem; __u16 tid; /* The 2 byte tree id */ __u16 Flags; /* optional support bits */ enum statusEnum tidStatus; - atomic_t useCount; /* how many mounts (explicit or implicit) to this share */ + atomic_t useCount; /* how many explicit/implicit mounts to share */ #ifdef CONFIG_CIFS_STATS atomic_t num_smbs_sent; atomic_t num_writes; @@ -257,7 +257,7 @@ struct cifsTconInfo { spinlock_t stat_lock; #endif /* CONFIG_CIFS_STATS */ FILE_SYSTEM_DEVICE_INFO fsDevInfo; - FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ + FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ FILE_SYSTEM_UNIX_INFO fsUnixInfo; unsigned retry:1; unsigned nocase:1; @@ -308,7 +308,6 @@ struct cifsFileInfo { 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 */ - unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ struct cifs_search_info srch_inf; }; @@ -523,16 +522,16 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ GLOBAL_EXTERN struct list_head GlobalOplock_Q; GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */ -GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */ +GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q;/* DirNotify response queue */ /* * Global transaction id (XID) information */ GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ -GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ +GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ -GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */ - /* on midQ entries */ +GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */ + /* on midQ entries */ GLOBAL_EXTERN char Local_System_Name[15]; /* @@ -554,7 +553,7 @@ GLOBAL_EXTERN atomic_t smBufAllocCount; GLOBAL_EXTERN atomic_t midCount; /* Misc globals */ -GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions +GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions to be established on existing mount if we have the uid/password or Kerberos credential or equivalent for current user */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 135941738d9d..e714803a52dc 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -426,6 +426,10 @@ typedef struct lanman_neg_rsp { unsigned char EncryptionKey[1]; } __attribute__((packed)) LANMAN_NEG_RSP; +#define READ_RAW_ENABLE 1 +#define WRITE_RAW_ENABLE 2 +#define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE) + typedef struct negotiate_rsp { struct smb_hdr hdr; /* wct = 17 */ __le16 DialectIndex; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 77cca3809467..0442c3b36799 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -411,8 +411,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) return rc; pSMB->hdr.Mid = GetNextMid(server); pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; -/* if (extended_security) - pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/ + if((extended_security & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) + pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; count = 0; for(i=0;iDialectIndex)); - /* Check wct = 1 error case */ - if((pSMBr->hdr.WordCount < 13) - || (pSMBr->DialectIndex == BAD_PROT)) { - /* core returns wct = 1, but we do not ask for - core - otherwise it just comes when dialect - index is -1 indicating we could not negotiate - a common dialect */ + if (rc != 0) + goto neg_err_exit; + + cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); + /* Check wct = 1 error case */ + if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) { + /* core returns wct = 1, but we do not ask for core - otherwise + small wct just comes when dialect index is -1 indicating we + could not negotiate a common dialect */ + rc = -EOPNOTSUPP; + goto neg_err_exit; +#ifdef CONFIG_CIFS_WEAK_PW_HASH + } else if((pSMBr->hdr.WordCount == 13) + && (pSMBr->DialectIndex == LANMAN_PROT)) { + struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; + + if((extended_security & CIFSSEC_MAY_LANMAN) || + (extended_security & CIFSSEC_MAY_PLNTXT)) + server->secType = LANMAN; + else { + cERROR(1, ("mount failed weak security disabled" + " in /proc/fs/cifs/SecurityFlags")); rc = -EOPNOTSUPP; goto neg_err_exit; -#ifdef CONFIG_CIFS_WEAK_PW_HASH - } else if((pSMBr->hdr.WordCount == 13) - && (pSMBr->DialectIndex == LANMAN_PROT)) { - struct lanman_neg_rsp * rsp = - (struct lanman_neg_rsp *)pSMBr; - - if((extended_security & CIFSSEC_MAY_LANMAN) || - (extended_security & CIFSSEC_MAY_PLNTXT)) - server->secType = LANMAN; - else { - cERROR(1, ("mount failed weak security disabled" - " in /proc/fs/cifs/SecurityFlags")); - rc = -EOPNOTSUPP; - goto neg_err_exit; - } - server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); - server->maxReq = le16_to_cpu(rsp->MaxMpxCount); - server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), + } + server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); + server->maxReq = le16_to_cpu(rsp->MaxMpxCount); + server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); + GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); + /* even though we do not use raw we might as well set this + accurately, in case we ever find a need for it */ + if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { + server->maxRw = 0xFF00; + server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; + } else { + server->maxRw = 0;/* we do not need to use raw anyway */ + server->capabilities = CAP_MPX_MODE; + } + server->timeZone = le16_to_cpu(rsp->ServerTimeZone); - /* BB what do we do with raw mode? BB */ - server->timeZone = le16_to_cpu(rsp->ServerTimeZone); - /* Do we have to set signing flags? no signing - was available LANMAN - default should be ok */ + /* BB get server time for time conversions and add + code to use it and timezone since this is not UTC */ - /* BB FIXME set default dummy capabilities since - they are not returned by the server in this dialect */ + if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { + memcpy(server->cryptKey, rsp->EncryptionKey, + CIFS_CRYPTO_KEY_SIZE); + } else if (server->secMode & SECMODE_PW_ENCRYPT) { + rc = -EIO; /* need cryptkey unless plain text */ + goto neg_err_exit; + } - /* get server time for time conversions and add - code to use it and timezone since this is not UTC */ - - if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { - memcpy(server->cryptKey, rsp->EncryptionKey, - CIFS_CRYPTO_KEY_SIZE); - } else { - rc = -EIO; - goto neg_err_exit; - } - - cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ + cFYI(1,("LANMAN negotiated")); + /* we will not end up setting signing flags - as no signing + was in LANMAN and server did not return the flags on */ + goto signing_check; #else /* weak security disabled */ - } else if(pSMBr->hdr.WordCount == 13) { - cERROR(1,("mount failed, cifs module not built " - "with CIFS_WEAK_PW_HASH support")); + } else if(pSMBr->hdr.WordCount == 13) { + cERROR(1,("mount failed, cifs module not built " + "with CIFS_WEAK_PW_HASH support")); rc = -EOPNOTSUPP; #endif /* WEAK_PW_HASH */ - goto neg_err_exit; - } else if(pSMBr->hdr.WordCount != 17) { - /* unknown wct */ - rc = -EOPNOTSUPP; - goto neg_err_exit; - } + goto neg_err_exit; + } else if(pSMBr->hdr.WordCount != 17) { + /* unknown wct */ + rc = -EOPNOTSUPP; + goto neg_err_exit; + } + /* else wct == 17 NTLM */ + server->secMode = pSMBr->SecurityMode; + if((server->secMode & SECMODE_USER) == 0) + cFYI(1,("share mode security")); - server->secMode = pSMBr->SecurityMode; - if((server->secMode & SECMODE_USER) == 0) - cFYI(1,("share mode security")); - - if((server->secMode & SECMODE_PW_ENCRYPT) == 0) + if((server->secMode & SECMODE_PW_ENCRYPT) == 0) #ifdef CONFIG_CIFS_WEAK_PW_HASH - if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) + if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) #endif /* CIFS_WEAK_PW_HASH */ - cERROR(1,("Server requests plain text password" - " but client support disabled")); + cERROR(1,("Server requests plain text password" + " but client support disabled")); - if(extended_security & CIFSSEC_MUST_NTLMV2) - server->secType = NTLMv2; - else - server->secType = NTLM; - /* else krb5 ... */ + if(extended_security & CIFSSEC_MUST_NTLMV2) + server->secType = NTLMv2; + else + server->secType = NTLM; + /* else krb5 ... */ - /* one byte - no need to convert this or EncryptionKeyLen - from little endian */ - server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); - /* probably no need to store and check maxvcs */ - server->maxBuf = - min(le32_to_cpu(pSMBr->MaxBufferSize), + /* one byte, so no need to convert this or EncryptionKeyLen from + little endian */ + server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); + /* probably no need to store and check maxvcs */ + server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize), (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); - server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); - cFYI(0, ("Max buf = %d", ses->server->maxBuf)); - GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); - server->capabilities = le32_to_cpu(pSMBr->Capabilities); - server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); - /* BB with UTC do we ever need to be using srvr timezone? */ - if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { - memcpy(server->cryptKey, pSMBr->u.EncryptionKey, - CIFS_CRYPTO_KEY_SIZE); - } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) - && (pSMBr->EncryptionKeyLength == 0)) { - /* decode security blob */ - } else + server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); + cFYI(0, ("Max buf = %d", ses->server->maxBuf)); + GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); + server->capabilities = le32_to_cpu(pSMBr->Capabilities); + server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); + if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { + memcpy(server->cryptKey, pSMBr->u.EncryptionKey, + CIFS_CRYPTO_KEY_SIZE); + } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) + && (pSMBr->EncryptionKeyLength == 0)) { + /* decode security blob */ + } else if (server->secMode & SECMODE_PW_ENCRYPT) { + rc = -EIO; /* no crypt key only if plain text pwd */ + goto neg_err_exit; + } + + /* BB might be helpful to save off the domain of server here */ + + if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && + (server->capabilities & CAP_EXTENDED_SECURITY)) { + count = pSMBr->ByteCount; + if (count < 16) rc = -EIO; - - /* BB might be helpful to save off the domain of server here */ - - if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && - (server->capabilities & CAP_EXTENDED_SECURITY)) { - count = pSMBr->ByteCount; - 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 + 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 { - rc = decode_negTokenInit(pSMBr->u. - extended_response. - SecurityBlob, - count - 16, - &server->secType); - if(rc == 1) { - /* BB Need to fill struct for sessetup here */ - rc = -EOPNOTSUPP; - } else { - rc = -EINVAL; + pSMBr->u.extended_response.GUID, + 16); } + } else + memcpy(server->server_GUID, + pSMBr->u.extended_response.GUID, 16); + } else { + rc = decode_negTokenInit(pSMBr->u.extended_response. + SecurityBlob, + count - 16, + &server->secType); + if(rc == 1) { + /* BB Need to fill struct for sessetup here */ + rc = -EOPNOTSUPP; + } else { + rc = -EINVAL; } - } else - server->capabilities &= ~CAP_EXTENDED_SECURITY; - if(sign_CIFS_PDUs == FALSE) { - if(server->secMode & SECMODE_SIGN_REQUIRED) - cERROR(1, - ("Server requires /proc/fs/cifs/PacketSigningEnabled")); - server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); - } else if(sign_CIFS_PDUs == 1) { - if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) - server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); } - + } else + server->capabilities &= ~CAP_EXTENDED_SECURITY; + +signing_check: + if(sign_CIFS_PDUs == FALSE) { + if(server->secMode & SECMODE_SIGN_REQUIRED) + cERROR(1,("Server requires " + "/proc/fs/cifs/PacketSigningEnabled to be on")); + server->secMode &= + ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); + } else if(sign_CIFS_PDUs == 1) { + if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) + server->secMode &= + ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); + } else if(sign_CIFS_PDUs == 2) { + if((server->secMode & + (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) { + cERROR(1,("signing required but server lacks support")); + } } neg_err_exit: cifs_buf_release(pSMB); + + cFYI(1,("negprot rc %d",rc)); return rc; } diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index a52aacb3feff..76a09f5f804f 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -323,7 +323,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, enum securityEnum type; __u16 action; int bytes_remaining; - + + cFYI(1,("new sess setup")); if(ses == NULL) return -EINVAL; From 9312f6754d4b2d3ce27c21b16fb92923ce92a411 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 4 Jun 2006 22:21:07 +0000 Subject: [PATCH 011/556] [CIFS] Fix mask so can set new cifs security flags properly Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 6 ++---- fs/cifs/cifssmb.c | 2 +- fs/cifs/sess.c | 5 +++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 7c0015a96959..2f55edf2eeea 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -860,8 +860,6 @@ security_flags_write(struct file *file, const char __user *buffer, char flags_string[12]; char c; - cERROR(1,("size %ld",count)); /* BB removeme BB */ - if((count < 1) || (count > 11)) return -EINVAL; @@ -883,14 +881,14 @@ security_flags_write(struct file *file, const char __user *buffer, flags = simple_strtoul(flags_string, NULL, 0); - cERROR(1,("sec flags 0x%x", flags)); /* BB FIXME make cFYI */ + cFYI(1,("sec flags 0x%x", flags)); if(flags <= 0) { cERROR(1,("invalid security flags %s",flags_string)); return -EINVAL; } - if((flags & CIFSSEC_MASK) != CIFSSEC_MASK) { + if(flags & ~CIFSSEC_MASK) { cERROR(1,("attempt to set unsupported security flags 0x%d", flags & ~CIFSSEC_MASK)); return -EINVAL; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 0442c3b36799..acae58313b0c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -504,7 +504,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) #endif /* CIFS_WEAK_PW_HASH */ cERROR(1,("Server requests plain text password" " but client support disabled")); - + if(extended_security & CIFSSEC_MUST_NTLMV2) server->secType = NTLMv2; else diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 76a09f5f804f..1fe9461c6dca 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -339,9 +339,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, return -EOPNOTSUPP; #endif wct = 10; /* lanman 2 style sessionsetup */ - } else if((type == NTLM) || (type == NTLMv2)) /* NTLMv2 may retry NTLM */ + } else if((type == NTLM) || (type == NTLMv2)) { + /* For NTLMv2 failures eventually may need to retry NTLM */ wct = 13; /* old style NTLM sessionsetup */ - else /* same size for negotiate or auth, NTLMSSP or extended security */ + } else /* same size for negotiate or auth, NTLMSSP or extended security */ wct = 12; rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, From f64b23ae4aef9f69d71ea41529a188acd5ab4930 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 5 Jun 2006 05:27:37 +0000 Subject: [PATCH 012/556] [CIFS] NTLMv2 support part 2 Still need to fill in response structure and check that hash works Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 2 ++ fs/cifs/cifspdu.h | 27 ++++++++++++++++++++++++--- fs/cifs/sess.c | 13 +++++++++---- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 3ae964bbfdc3..24ab770f60dc 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -306,6 +306,8 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) { + /* BB FIXME - update struct ntlmv2_response and change calling convention + of this function */ struct HMACMD5Context context; memcpy(v2_session_response + 8, ses->server->cryptKey,8); /* gen_blob(v2_session_response + 16); */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e714803a52dc..503b7e32ede3 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -117,7 +117,6 @@ * Size of the session key (crypto key encrypted with the password */ #define CIFS_SESS_KEY_SIZE (24) -#define V2_SESS_KEY_SIZE (86) /* * Maximum user name length @@ -539,7 +538,7 @@ typedef union smb_com_session_setup_andx { /* unsigned char * NativeOS; */ /* unsigned char * NativeLanMan; */ /* unsigned char * PrimaryDomain; */ - } __attribute__((packed)) resp; /* NTLM response format (with or without extended security */ + } __attribute__((packed)) resp; /* NTLM response with or without extended sec*/ struct { /* request format */ struct smb_hdr hdr; /* wct = 10 */ @@ -573,6 +572,26 @@ typedef union smb_com_session_setup_andx { } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */ } __attribute__((packed)) SESSION_SETUP_ANDX; +/* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */ + +struct ntlmssp2_name { + __le16 type; + __le16 length; +/* char name[length]; */ +} __attribute__((packed)); + +struct ntlmv2_resp { + char ntlmv2_hash[CIFS_ENCPWD_SIZE]; + __le32 blob_sign; + __u32 reserved; + __le64 time; + __u64 client_chal; /* random */ + __u32 reserved2; + struct ntlmssp2_name names[1]; + /* array of name entries could follow ending in minimum 4 byte struct */ +} __attribute__((packed)); + + #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" /* Capabilities bits (for NTLM SessSetup request) */ @@ -603,7 +622,9 @@ typedef struct smb_com_tconx_req { } __attribute__((packed)) TCONX_REQ; typedef struct smb_com_tconx_rsp { - struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ + struct smb_hdr hdr; /* wct = 3 note that Win2000 has sent wct = 7 + in some cases on responses. Four unspecified + words followed OptionalSupport */ __u8 AndXCommand; __u8 AndXReserved; __le16 AndXOffset; diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 1fe9461c6dca..9ce628df29b4 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -411,7 +411,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else if (type == NTLMv2) { - char * v2_sess_key = kmalloc(V2_SESS_KEY_SIZE, GFP_KERNEL); + char * v2_sess_key = kmalloc(sizeof(struct ntlmv2_resp), + GFP_KERNEL); + + /* BB FIXME change all users of v2_sess_key to + struct ntlmv2_resp */ if(v2_sess_key == NULL) { cifs_small_buf_release(smb_buf); @@ -425,7 +429,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(V2_SESS_KEY_SIZE); + cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ CalcNTLMv2_response(ses, v2_sess_key); @@ -438,8 +442,9 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE); bcc_ptr += LM2_SESS_KEY_SIZE; */ - memcpy(bcc_ptr, (char *)v2_sess_key, V2_SESS_KEY_SIZE); - bcc_ptr += V2_SESS_KEY_SIZE; + memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp)); + bcc_ptr += sizeof(struct ntlmv2_resp); + kfree(v2_sess_key); if(ses->capabilities & CAP_UNICODE) unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); else From 6d027cfdb19c26df3151a519ed55acfe2c4cb7c3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 5 Jun 2006 16:26:05 +0000 Subject: [PATCH 013/556] [CIFS] NTLMv2 support part 3 Response struct filled in exacty for 16 byte hash which we need to check more to make sure it works. Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 17 +++++++++++++++-- fs/cifs/cifspdu.h | 2 +- fs/cifs/cifsproto.h | 1 + fs/cifs/sess.c | 6 +++--- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 24ab770f60dc..09f94617e534 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -27,6 +27,7 @@ #include "cifs_unicode.h" #include "cifsproto.h" #include +#include /* Calculate and return the CIFS signature based on the mac key and the smb pdu */ /* the 16 byte signature must be allocated by the caller */ @@ -304,10 +305,22 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) } #endif /* CIFS_WEAK_PW_HASH */ +void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) +{ + struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; + + buf->blob_signature = cpu_to_le32(0x00000101); + buf->reserved = 0; + buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); + buf->reserved2 = 0; + buf->names[0].type = 0; + buf->names[0].length = 0; + /* calculate buf->ntlmv2_hash */ +} + void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) { - /* BB FIXME - update struct ntlmv2_response and change calling convention - of this function */ struct HMACMD5Context context; memcpy(v2_session_response + 8, ses->server->cryptKey,8); /* gen_blob(v2_session_response + 16); */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 503b7e32ede3..5250b93d3098 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -582,7 +582,7 @@ struct ntlmssp2_name { struct ntlmv2_resp { char ntlmv2_hash[CIFS_ENCPWD_SIZE]; - __le32 blob_sign; + __le32 blob_signature; __u32 reserved; __le64 time; __u64 client_chal; /* random */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 59b037f14511..824afb937a6f 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -287,6 +287,7 @@ extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); +extern void setup_ntlmv2_rsp(const struct cifsSesInfo *, char *); #ifdef CONFIG_CIFS_WEAK_PW_HASH extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 9ce628df29b4..c6fd01f55e90 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -411,8 +411,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else if (type == NTLMv2) { - char * v2_sess_key = kmalloc(sizeof(struct ntlmv2_resp), - GFP_KERNEL); + char * v2_sess_key = + kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL); /* BB FIXME change all users of v2_sess_key to struct ntlmv2_resp */ @@ -432,7 +432,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ - CalcNTLMv2_response(ses, v2_sess_key); + setup_ntlmv2_rsp(ses, v2_sess_key); if(first_time) /* should this be moved into common code with similar ntlmv2 path? */ /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, From a8ee03441f66e0674e641c0cbe1a9534cdee968f Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 5 Jun 2006 23:34:19 +0000 Subject: [PATCH 014/556] [CIFS] NTLMv2 support part 4 Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 2 +- fs/cifs/cifsencrypt.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 2f55edf2eeea..96abeb738978 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -889,7 +889,7 @@ security_flags_write(struct file *file, const char __user *buffer, } if(flags & ~CIFSSEC_MASK) { - cERROR(1,("attempt to set unsupported security flags 0x%d", + cERROR(1,("attempt to set unsupported security flags 0x%x", flags & ~CIFSSEC_MASK)); return -EINVAL; } diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 09f94617e534..8bcb1da3270e 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -305,8 +305,44 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) } #endif /* CIFS_WEAK_PW_HASH */ +static int calc_ntlmv2_hash(const struct cifsSesInfo *ses, + char * ntv2_hash) +{ + int rc = 0; + int len; + char nt_hash[16]; + struct HMACMD5Context * pctxt; + + pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); + + if(pctxt == NULL) + return -ENOMEM; + + /* calculate md4 hash of password */ + E_md4hash(ses->password, nt_hash); + + /* convERT Domainname to unicode and uppercase */ + hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); + + /* convert ses->userName to unicode and uppercase */ + + /* len = ... */ /* BB FIXME BB */ + + /* hmac_md5_update(user, len, pctxt); */ + + /* convert ses->domainName to unicode and uppercase */ + + /* len = ... */ /* BB FIXME BB */ + /* hmac_md5_update(domain, len, pctxt); */ + + hmac_md5_final(ntv2_hash, pctxt); + + return rc; +} + void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) { + int rc; struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; buf->blob_signature = cpu_to_le32(0x00000101); @@ -316,7 +352,11 @@ void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) buf->reserved2 = 0; buf->names[0].type = 0; buf->names[0].length = 0; + /* calculate buf->ntlmv2_hash */ + rc = calc_ntlmv2_hash(ses,buf->ntlmv2_hash); + if(rc) + cERROR(1,("could not get v2 hash rc %d",rc)); } void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) From 5bafd76593f060540acbea3b61e3087e009aa269 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 7 Jun 2006 00:18:43 +0000 Subject: [PATCH 015/556] [CIFS] Add support for readdir to legacy servers Fixes oops to OS/2 on ls and removes redundant NTCreateX calls to servers which do not support NT SMBs. Key operations to OS/2 work. Signed-off-by: Steve French --- fs/cifs/CHANGES | 4 ++ fs/cifs/cifspdu.h | 29 +++++++-- fs/cifs/dir.c | 11 +++- fs/cifs/file.c | 9 ++- fs/cifs/readdir.c | 150 +++++++++++++++++++++++++++++++++------------- 5 files changed, 153 insertions(+), 50 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index b878dfcff0f0..7e0058bc3dd9 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -2,6 +2,10 @@ Version 1.44 ------------ Rewritten sessionsetup support, including support for legacy SMB session setup needed for OS/2 and older servers such as Windows 95 and 98. +Fix oops on ls to OS/2 servers. Add support for level 1 FindFirst +so we can do search (ls etc.) to OS/2. Do not send NTCreateX +or recent levels of FindFirst unless server says it supports NT SMBs +(instead use legacy equivalents from LANMAN dialect). Version 1.43 ------------ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 5250b93d3098..86239023545b 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1374,6 +1374,9 @@ struct smb_t2_rsp { #define SMB_FILE_MAXIMUM_INFO 0x40d /* Find File infolevels */ +#define SMB_FIND_FILE_INFO_STANDARD 0x001 +#define SMB_FIND_FILE_QUERY_EA_SIZE 0x002 +#define SMB_FIND_FILE_QUERY_EAS_FROM_LIST 0x003 #define SMB_FIND_FILE_DIRECTORY_INFO 0x101 #define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 #define SMB_FIND_FILE_NAMES_INFO 0x103 @@ -1998,7 +2001,8 @@ typedef struct { struct file_allocation_info { __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ -} __attribute__((packed)); /* size used on disk, level 0x103 for set, 0x105 for query */ +} __attribute__((packed)); /* size used on disk, for level 0x103 for set, + 0x105 for query */ struct file_end_of_file_info { __le64 FileSize; /* offset to end of file */ @@ -2105,7 +2109,7 @@ typedef struct { __le32 ExtFileAttributes; __le32 FileNameLength; char FileName[1]; -} __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */ +} __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF resp data */ typedef struct { __le32 NextEntryOffset; @@ -2120,7 +2124,7 @@ typedef struct { __le32 FileNameLength; __le32 EaSize; /* length of the xattrs */ char FileName[1]; -} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 FF response data area */ +} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */ typedef struct { __le32 NextEntryOffset; @@ -2137,7 +2141,7 @@ typedef struct { __le32 Reserved; __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ char FileName[1]; -} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF response data area */ +} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */ typedef struct { __le32 NextEntryOffset; @@ -2155,7 +2159,22 @@ typedef struct { __u8 Reserved; __u8 ShortName[12]; char FileName[1]; -} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ +} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */ + +typedef struct { + __u32 ResumeKey; + __le16 CreationDate; /* SMB Date */ + __le16 CreationTime; /* SMB Time */ + __le16 LastAccessDate; + __le16 LastAccessTime; + __le16 LastWriteDate; + __le16 LastWriteTime; + __le32 DataSize; /* File Size (EOF) */ + __le32 AllocationSize; + __le16 Attributes; /* verify not u32 */ + __u8 FileNameLength; + char FileName[1]; +} __attribute__((packed)) FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */ struct win_dev { diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e6ed64e94b7b..ba4cbe9b0684 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -178,11 +178,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, FreeXid(xid); return -ENOMEM; } - - rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, + if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &fileHandle, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + else + rc = -EIO; /* no NT SMB support fall into legacy open below */ + if(rc == -EIO) { /* old server, retry the open legacy style */ rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, @@ -369,6 +372,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + /* BB FIXME - add handling for backlevel servers + which need legacy open and check for all + calls to SMBOpen for fallback to + SMBLeagcyOpen */ if(!rc) { /* BB Do not bother to decode buf since no local inode yet to put timestamps in, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index d62e29fe91f2..fafdcdffba62 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -260,10 +260,15 @@ int cifs_open(struct inode *inode, struct file *file) rc = -ENOMEM; goto out; } - rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, - CREATE_NOT_DIR, &netfid, &oplock, buf, + + if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, + desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + else + rc = -EIO; /* no NT SMB support fall into legacy open below */ + if (rc == -EIO) { /* Old server, try legacy style OpenX */ rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index e3e762d774df..03bbcb377913 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -109,32 +109,52 @@ static int construct_dentry(struct qstr *qstring, struct file *file, return rc; } -static void fill_in_inode(struct inode *tmp_inode, - FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode) +static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, + char * buf, int *pobject_type, int isNewInode) { loff_t local_size; struct timespec local_mtime; struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); - __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); - __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize); - __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); - - cifsInfo->cifsAttrs = attr; - cifsInfo->time = jiffies; + __u32 attr; + __u64 allocation_size; + __u64 end_of_file; /* save mtime and size */ local_mtime = tmp_inode->i_mtime; local_size = tmp_inode->i_size; + if(new_buf_type) { + FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf; + + attr = le32_to_cpu(pfindData->ExtFileAttributes); + allocation_size = le64_to_cpu(pfindData->AllocationSize); + end_of_file = le64_to_cpu(pfindData->EndOfFile); + tmp_inode->i_atime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); + tmp_inode->i_mtime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); + tmp_inode->i_ctime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); + } else { /* legacy, OS2 and DOS style */ + FIND_FILE_STANDARD_INFO * pfindData = + (FIND_FILE_STANDARD_INFO *)buf; + + attr = le16_to_cpu(pfindData->Attributes); + allocation_size = le32_to_cpu(pfindData->AllocationSize); + end_of_file = le32_to_cpu(pfindData->DataSize); + tmp_inode->i_atime = CURRENT_TIME; + /* tmp_inode->i_mtime = BB FIXME - add dos time handling + tmp_inode->i_ctime = 0; BB FIXME */ + + } + /* Linux can not store file creation time unfortunately so ignore it */ - tmp_inode->i_atime = - cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); - tmp_inode->i_mtime = - cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); - tmp_inode->i_ctime = - cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); + + cifsInfo->cifsAttrs = attr; + cifsInfo->time = jiffies; + /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ /* 2767 perms - indicate mandatory locking */ /* BB fill in uid and gid here? with help from winbind? @@ -420,7 +440,10 @@ static int initiate_cifs_search(const int xid, struct file *file) ffirst_retry: /* test for Unix extensions */ if (pTcon->ses->capabilities & CAP_UNIX) { - cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; + cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; + } else if ((pTcon->ses->capabilities & + (CAP_NT_SMBS | CAP_NT_FIND)) == 0) { + cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD; } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; } else /* not srvinos - BB fixme add check for backlevel? */ { @@ -456,12 +479,19 @@ static int cifs_unicode_bytelen(char *str) return len << 1; } -static char *nxt_dir_entry(char *old_entry, char *end_of_smb) +static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) { char * new_entry; FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; - new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); + if(level == SMB_FIND_FILE_INFO_STANDARD) { + FIND_FILE_STANDARD_INFO * pfData; + pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo; + + new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) + + pfData->FileNameLength; + } else + new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); /* validate that new_entry is not past end of SMB */ if(new_entry >= end_of_smb) { @@ -469,7 +499,10 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb) ("search entry %p began after end of SMB %p old entry %p", new_entry, end_of_smb, old_entry)); return NULL; - } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) { + } else if(((level == SMB_FIND_FILE_INFO_STANDARD) && + (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) || + ((level != SMB_FIND_FILE_INFO_STANDARD) && + (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) { cERROR(1,("search entry %p extends after end of SMB %p", new_entry, end_of_smb)); return NULL; @@ -487,7 +520,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) char * filename = NULL; int len = 0; - if(cfile->srch_inf.info_level == 0x202) { + if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) { FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; filename = &pFindData->FileName[0]; if(cfile->srch_inf.unicode) { @@ -496,26 +529,34 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) /* BB should we make this strnlen of PATH_MAX? */ len = strnlen(filename, 5); } - } else if(cfile->srch_inf.info_level == 0x101) { + } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) { FILE_DIRECTORY_INFO * pFindData = (FILE_DIRECTORY_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); - } else if(cfile->srch_inf.info_level == 0x102) { + } else if(cfile->srch_inf.info_level == + SMB_FIND_FILE_FULL_DIRECTORY_INFO) { FILE_FULL_DIRECTORY_INFO * pFindData = (FILE_FULL_DIRECTORY_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); - } else if(cfile->srch_inf.info_level == 0x105) { + } else if(cfile->srch_inf.info_level == + SMB_FIND_FILE_ID_FULL_DIR_INFO) { SEARCH_ID_FULL_DIR_INFO * pFindData = (SEARCH_ID_FULL_DIR_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); - } else if(cfile->srch_inf.info_level == 0x104) { + } else if(cfile->srch_inf.info_level == + SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { FILE_BOTH_DIRECTORY_INFO * pFindData = (FILE_BOTH_DIRECTORY_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); + } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) { + FIND_FILE_STANDARD_INFO * pFindData = + (FIND_FILE_STANDARD_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); } else { cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); } @@ -651,10 +692,12 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry - cifsFile->srch_inf.entries_in_buffer; pos_in_buf = index_to_find - first_entry_in_buffer; - cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); + cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); + for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { /* go entry by entry figuring out which is first */ - current_entry = nxt_dir_entry(current_entry,end_of_smb); + current_entry = nxt_dir_entry(current_entry,end_of_smb, + cifsFile->srch_inf.info_level); } if((current_entry == NULL) && (i < pos_in_buf)) { /* BB fixme - check if we should flag this error */ @@ -681,7 +724,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, /* inode num, inode type and filename returned */ static int cifs_get_name_from_search_buf(struct qstr *pqst, char *current_entry, __u16 level, unsigned int unicode, - struct cifs_sb_info * cifs_sb, ino_t *pinum) + struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum) { int rc = 0; unsigned int len = 0; @@ -725,10 +768,22 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, (FILE_BOTH_DIRECTORY_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); + } else if(level == SMB_FIND_FILE_INFO_STANDARD) { + FIND_FILE_STANDARD_INFO * pFindData = + (FIND_FILE_STANDARD_INFO *)current_entry; + filename = &pFindData->FileName[0]; + /* one byte length, no name conversion */ + len = (unsigned int)pFindData->FileNameLength; } else { cFYI(1,("Unknown findfirst level %d",level)); return -EINVAL; } + + if(len > max_len) { + cERROR(1,("bad search response length %d past smb end", len)); + return -EINVAL; + } + if(unicode) { /* BB fixme - test with long names */ /* Note converted filename can be longer than in unicode */ @@ -748,7 +803,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, } static int cifs_filldir(char *pfindEntry, struct file *file, - filldir_t filldir, void *direntry, char *scratch_buf) + filldir_t filldir, void *direntry, char *scratch_buf, int max_len) { int rc = 0; struct qstr qstring; @@ -784,6 +839,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file, rc = cifs_get_name_from_search_buf(&qstring,pfindEntry, pCifsF->srch_inf.info_level, pCifsF->srch_inf.unicode,cifs_sb, + max_len, &inum /* returned */); if(rc) @@ -805,13 +861,16 @@ static int cifs_filldir(char *pfindEntry, struct file *file, /* we pass in rc below, indicating whether it is a new inode, so we can figure out whether to invalidate the inode cached data if the file has changed */ - if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { + if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) unix_fill_in_inode(tmp_inode, - (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc); - } else { - fill_in_inode(tmp_inode, - (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); - } + (FILE_UNIX_INFO *)pfindEntry, + &obj_type, rc); + else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) + fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */, + pfindEntry, &obj_type, rc); + else + fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); + rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, tmp_inode->i_ino,obj_type); @@ -871,6 +930,12 @@ static int cifs_save_resume_key(const char *current_entry, filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); cifsFile->srch_inf.resume_key = pFindData->FileIndex; + } else if(level == SMB_FIND_FILE_INFO_STANDARD) { + FIND_FILE_STANDARD_INFO * pFindData = + (FIND_FILE_STANDARD_INFO *)current_entry; + filename = &pFindData->FileName[0]; + /* one byte length, no name conversion */ + len = (unsigned int)pFindData->FileNameLength; } else { cFYI(1,("Unknown findfirst level %d",level)); return -EINVAL; @@ -891,6 +956,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) int num_to_fill = 0; char * tmp_buf = NULL; char * end_of_smb; + int max_len; xid = GetXid(); @@ -966,10 +1032,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) goto rddir2_exit; } cFYI(1,("loop through %d times filling dir for net buf %p", - num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); - end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + - smbCalcSize((struct smb_hdr *) - cifsFile->srch_inf.ntwrk_buf_start); + num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); + max_len = smbCalcSize((struct smb_hdr *) + cifsFile->srch_inf.ntwrk_buf_start); + end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; + /* To be safe - for UCS to UTF-8 with strings loaded with the rare long characters alloc more to account for such multibyte target UTF-8 characters. cifs_unicode.c, @@ -984,8 +1051,8 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) } /* if buggy server returns . and .. late do we want to check for that here? */ - rc = cifs_filldir(current_entry, file, - filldir, direntry,tmp_buf); + rc = cifs_filldir(current_entry, file, + filldir, direntry, tmp_buf, max_len); file->f_pos++; if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) { @@ -994,8 +1061,9 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) cifs_save_resume_key(current_entry,cifsFile); break; } else - current_entry = nxt_dir_entry(current_entry, - end_of_smb); + current_entry = + nxt_dir_entry(current_entry, end_of_smb, + cifsFile->srch_inf.info_level); } kfree(tmp_buf); break; From 1717ffc58850dfa9e08b4977f8d0323cb3336863 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 8 Jun 2006 05:41:32 +0000 Subject: [PATCH 016/556] [CIFS] NTLMv2 support part 5 NTLMv2 authentication (stronger authentication than default NTLM) which many servers support now works. There was a problem with the construction of the security blob in the older code. Currently requires /proc/fs/cifs/Experimental to be set to 2 and /proc/fs/cifs/SecurityFlags to be set to 0x4004 (to require using NTLMv2 instead of default of NTLM) Next we will check signing to make sure optional NTLMv2 packet signing also works. Signed-off-by: Steve French --- fs/cifs/CHANGES | 4 ++- fs/cifs/cifsencrypt.c | 60 +++++++++++++++++++++++++++++-------------- fs/cifs/cifsproto.h | 8 +++--- fs/cifs/sess.c | 2 +- 4 files changed, 50 insertions(+), 24 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 7e0058bc3dd9..79a202b8f66a 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -5,7 +5,9 @@ session setup needed for OS/2 and older servers such as Windows 95 and 98. Fix oops on ls to OS/2 servers. Add support for level 1 FindFirst so we can do search (ls etc.) to OS/2. Do not send NTCreateX or recent levels of FindFirst unless server says it supports NT SMBs -(instead use legacy equivalents from LANMAN dialect). +(instead use legacy equivalents from LANMAN dialect). Fix to allow +NTLMv2 authentication support (now can use stronger password hashing +on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004) Version 1.43 ------------ diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 8bcb1da3270e..a89efaf78a26 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -212,7 +212,8 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password) return 0; } -int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info) +int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, + const struct nls_table * nls_info) { char temp_hash[16]; struct HMACMD5Context ctx; @@ -305,13 +306,15 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) } #endif /* CIFS_WEAK_PW_HASH */ -static int calc_ntlmv2_hash(const struct cifsSesInfo *ses, - char * ntv2_hash) +static int calc_ntlmv2_hash(struct cifsSesInfo *ses, + const struct nls_table * nls_cp) { int rc = 0; int len; char nt_hash[16]; struct HMACMD5Context * pctxt; + wchar_t * user; + wchar_t * domain; pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); @@ -321,26 +324,44 @@ static int calc_ntlmv2_hash(const struct cifsSesInfo *ses, /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash); - /* convERT Domainname to unicode and uppercase */ + /* convert Domainname to unicode and uppercase */ hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); /* convert ses->userName to unicode and uppercase */ - - /* len = ... */ /* BB FIXME BB */ - - /* hmac_md5_update(user, len, pctxt); */ + len = strlen(ses->userName); + user = kmalloc(2 + (len * 2), GFP_KERNEL); + if(user == NULL) + goto calc_exit_2; + len = cifs_strtoUCS(user, ses->userName, len, nls_cp); + UniStrupr(user); + hmac_md5_update((char *)user, 2*len, pctxt); /* convert ses->domainName to unicode and uppercase */ + if(ses->domainName) { + len = strlen(ses->domainName); - /* len = ... */ /* BB FIXME BB */ - /* hmac_md5_update(domain, len, pctxt); */ + domain = kmalloc(2 + (len * 2), GFP_KERNEL); + if(domain == NULL) + goto calc_exit_1; + len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp); + UniStrupr(domain); - hmac_md5_final(ntv2_hash, pctxt); + hmac_md5_update((char *)domain, 2*len, pctxt); + + kfree(domain); + } +calc_exit_1: + kfree(user); +calc_exit_2: + /* BB FIXME what about bytes 24 through 40 of the signing key? + compare with the NTLM example */ + hmac_md5_final(ses->server->mac_signing_key, pctxt); return rc; } -void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) +void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, + const struct nls_table * nls_cp) { int rc; struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; @@ -348,27 +369,28 @@ void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) buf->blob_signature = cpu_to_le32(0x00000101); buf->reserved = 0; buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); - get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); + get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); buf->reserved2 = 0; buf->names[0].type = 0; buf->names[0].length = 0; /* calculate buf->ntlmv2_hash */ - rc = calc_ntlmv2_hash(ses,buf->ntlmv2_hash); + rc = calc_ntlmv2_hash(ses, nls_cp); if(rc) cERROR(1,("could not get v2 hash rc %d",rc)); + CalcNTLMv2_response(ses, resp_buf); } -void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) +void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response) { struct HMACMD5Context context; + /* rest of v2 struct already generated */ memcpy(v2_session_response + 8, ses->server->cryptKey,8); - /* gen_blob(v2_session_response + 16); */ hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context); - hmac_md5_update(ses->server->cryptKey,8,&context); -/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ + hmac_md5_update(v2_session_response+8, + sizeof(struct ntlmv2_resp) - 8, &context); hmac_md5_final(v2_session_response,&context); - cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); /* BB removeme BB */ +/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ } diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 824afb937a6f..7ffd5b0d63cf 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -285,9 +285,11 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, __u32 expected_sequence_number); extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); -extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); -extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); -extern void setup_ntlmv2_rsp(const struct cifsSesInfo *, char *); +extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, + const struct nls_table *); +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 */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c6fd01f55e90..c039b54206aa 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -432,7 +432,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ - setup_ntlmv2_rsp(ses, v2_sess_key); + setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); if(first_time) /* should this be moved into common code with similar ntlmv2 path? */ /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, From 6344a423e5806d138923caa1d7699f3b7809fe43 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 12 Jun 2006 04:18:35 +0000 Subject: [PATCH 017/556] [CIFS] fix minor compile warning when config_cifs_weak_security is off Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index acae58313b0c..271a037a386f 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -569,7 +569,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) } else server->capabilities &= ~CAP_EXTENDED_SECURITY; +#ifdef CONFIG_CIFS_WEAK_PW_HASH signing_check: +#endif if(sign_CIFS_PDUs == FALSE) { if(server->secMode & SECMODE_SIGN_REQUIRED) cERROR(1,("Server requires " From 0fd1ffe0633b4b039b343b753598e6df435e034d Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Tue, 13 Jun 2006 21:31:39 +0000 Subject: [PATCH 018/556] [CIFS] Fix suspend/resume problem which causes EIO on subsequent access to the mount. Signed-off-by: Pavel Machek Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- fs/cifs/connect.c | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 700570522b23..fb7c11c2c913 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -905,7 +905,7 @@ static int cifs_dnotify_thread(void * dummyarg) struct cifsSesInfo *ses; do { - if(try_to_freeze()) + if (try_to_freeze()) continue; set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(15*HZ); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e6f3d2fff6c0..faaf9eb15b9f 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -367,21 +367,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) continue; if (bigbuf == NULL) { bigbuf = cifs_buf_get(); - if(bigbuf == NULL) { - cERROR(1,("No memory for large SMB response")); + if (!bigbuf) { + cERROR(1, ("No memory for large SMB response")); msleep(3000); /* retry will check if exiting */ continue; } - } else if(isLargeBuf) { - /* we are reusing a dirtry large buf, clear its start */ + } else if (isLargeBuf) { + /* we are reusing a dirty large buf, clear its start */ memset(bigbuf, 0, sizeof (struct smb_hdr)); } if (smallbuf == NULL) { smallbuf = cifs_small_buf_get(); - if(smallbuf == NULL) { - cERROR(1,("No memory for SMB response")); + if (!smallbuf) { + cERROR(1, ("No memory for SMB response")); msleep(1000); /* retry will check if exiting */ continue; @@ -401,12 +401,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) kernel_recvmsg(csocket, &smb_msg, &iov, 1, 4, 0 /* BB see socket.h flags */); - if(server->tcpStatus == CifsExiting) { + if (server->tcpStatus == CifsExiting) { break; } else if (server->tcpStatus == CifsNeedReconnect) { - cFYI(1,("Reconnect after server stopped responding")); + cFYI(1, ("Reconnect after server stopped responding")); cifs_reconnect(server); - cFYI(1,("call to reconnect done")); + cFYI(1, ("call to reconnect done")); csocket = server->ssocket; continue; } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { @@ -415,15 +415,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) tcpStatus CifsNeedReconnect if server hung */ continue; } else if (length <= 0) { - if(server->tcpStatus == CifsNew) { - cFYI(1,("tcp session abend after SMBnegprot")); + if (server->tcpStatus == CifsNew) { + cFYI(1, ("tcp session abend after SMBnegprot")); /* some servers kill the TCP session rather than returning an SMB negprot error, in which case reconnecting here is not going to help, and so simply return error to mount */ break; } - if(length == -EINTR) { + if (!try_to_freeze() && (length == -EINTR)) { cFYI(1,("cifsd thread killed")); break; } From 89d17b9604ae502392e119dbdbf43f6067745715 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 20 Jun 2006 00:39:19 -0400 Subject: [PATCH 019/556] [AGPGART] Whitespace cleanups for ati-agp Signed-off-by: Dave Jones --- drivers/char/agp/ati-agp.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 06fd10ba0c5e..6db9b7f436aa 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -41,7 +41,6 @@ static struct gatt_mask ati_generic_masks[] = }; - typedef struct _ati_page_map { unsigned long *real; unsigned long __iomem *remapped; @@ -141,7 +140,8 @@ static int ati_create_gatt_pages(int nr_tables) ati_generic_private.num_tables = nr_tables; ati_generic_private.gatt_pages = tables; - if (retval != 0) ati_free_gatt_pages(); + if (retval != 0) + ati_free_gatt_pages(); return retval; } @@ -219,16 +219,16 @@ static int ati_configure(void) ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); if (is_r200()) - pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000); + pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000); else pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000); /* address to map too */ - /* + /* pci_read_config_dword(agp_bridge.dev, AGP_APBASE, &temp); agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr); - */ + */ writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID); readl(ati_generic_private.registers+ATI_GART_FEATURE_ID); /* PCI Posting.*/ @@ -321,9 +321,9 @@ static int ati_remove_memory(struct agp_memory * mem, off_t pg_start, unsigned long __iomem *cur_gatt; unsigned long addr; - if (type != 0 || mem->type != 0) { + if (type != 0 || mem->type != 0) return -EINVAL; - } + for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); @@ -502,9 +502,8 @@ found: bridge->dev = pdev; bridge->capndx = cap_ptr; - - bridge->driver = &ati_generic_bridge; + bridge->driver = &ati_generic_bridge; printk(KERN_INFO PFX "Detected Ati %s chipset\n", devs[j].chipset_name); From a4aec2622340e356e7dcd0e8fd05378dacb71c89 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 20 Jun 2006 00:42:04 -0400 Subject: [PATCH 020/556] [AGPGART] Suspend/Resume improvements for ATI AGP Based on patches in the Ubuntu kernel. Signed-off-by: Ben Collins Signed-off-by: Dave Jones --- drivers/char/agp/ati-agp.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 6db9b7f436aa..34bbd41f062a 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -245,19 +245,21 @@ static int ati_configure(void) #ifdef CONFIG_PM -static int agp_ati_resume(struct pci_dev *dev) -{ - pci_restore_state(dev); - - return ati_configure(); -} - static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state) { pci_save_state(dev); + pci_set_power_state (pdev, 3); return 0; } + +static int agp_ati_resume(struct pci_dev *dev) +{ + pci_set_power_state (pdev, 0); + pci_restore_state(dev); + + return ati_configure(); +} #endif /* @@ -545,8 +547,8 @@ static struct pci_driver agp_ati_pci_driver = { .probe = agp_ati_probe, .remove = agp_ati_remove, #ifdef CONFIG_PM - .resume = agp_ati_resume, .suspend = agp_ati_suspend, + .resume = agp_ati_resume, #endif }; From c5f2f261e7a47e4c72723cdcbe99e1bd771a81ea Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 20 Jun 2006 00:44:38 -0400 Subject: [PATCH 021/556] [AGPGART] Suspend/Resume support for nVidia nForce AGP. Based on a patch from the Ubuntu kernel. Signed-off-by: Ben Collins Signed-off-by: Dave Jones --- drivers/char/agp/nvidia-agp.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 4c67135c12d8..b3a53e7f3602 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -376,6 +376,31 @@ static void __devexit agp_nvidia_remove(struct pci_dev *pdev) agp_put_bridge(bridge); } +#ifdef CONFIG_PM +static int agp_nvidia_suspend(struct pci_dev *pdev, pm_message_t state) +{ + pci_save_state (pdev); + pci_set_power_state (pdev, 3); + + return 0; +} + +static int agp_nvidia_resume(struct pci_dev *pdev) +{ + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + + /* set power state 0 and restore PCI space */ + pci_set_power_state (pdev, 0); + pci_restore_state(pdev); + + /* reconfigure AGP hardware again */ + nvidia_configure(); + + return 0; +} +#endif + + static struct pci_device_id agp_nvidia_pci_table[] = { { .class = (PCI_CLASS_BRIDGE_HOST << 8), @@ -403,6 +428,10 @@ static struct pci_driver agp_nvidia_pci_driver = { .id_table = agp_nvidia_pci_table, .probe = agp_nvidia_probe, .remove = agp_nvidia_remove, +#ifdef CONFIG_PM + .suspend = agp_nvidia_suspend, + .resume = agp_nvidia_resume, +#endif }; static int __init agp_nvidia_init(void) From e05b59fe7927bc648ac3af3d59dc64a7ee6b22e2 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Wed, 19 Apr 2006 22:40:53 +0200 Subject: [PATCH 022/556] [WATCHDOG] Pre-Timeout flags Some watchdog timers support the concept of a "pretimeout" which occurs some time before the real timeout. The pretimeout can be delivered via an interrupt or NMI and can be used to panic the system when it occurs (so you get useful information instead of a blind reboot). Signed-off-by: Corey Minyard Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- Documentation/watchdog/watchdog-api.txt | 30 ++++++++++++++++++++++++- include/linux/watchdog.h | 3 +++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Documentation/watchdog/watchdog-api.txt b/Documentation/watchdog/watchdog-api.txt index 21ed51173662..7dc2c1c6f779 100644 --- a/Documentation/watchdog/watchdog-api.txt +++ b/Documentation/watchdog/watchdog-api.txt @@ -110,7 +110,31 @@ current timeout using the GETTIMEOUT ioctl. ioctl(fd, WDIOC_GETTIMEOUT, &timeout); printf("The timeout was is %d seconds\n", timeout); -Envinronmental monitoring: +Pretimeouts: + +Some watchdog timers can be set to have a trigger go off before the +actual time they will reset the system. This can be done with an NMI, +interrupt, or other mechanism. This allows Linux to record useful +information (like panic information and kernel coredumps) before it +resets. + + pretimeout = 10; + ioctl(fd, WDIOC_SETPRETIMEOUT, &pretimeout); + +Note that the pretimeout is the number of seconds before the time +when the timeout will go off. It is not the number of seconds until +the pretimeout. So, for instance, if you set the timeout to 60 seconds +and the pretimeout to 10 seconds, the pretimout will go of in 50 +seconds. Setting a pretimeout to zero disables it. + +There is also a get function for getting the pretimeout: + + ioctl(fd, WDIOC_GETPRETIMEOUT, &timeout); + printf("The pretimeout was is %d seconds\n", timeout); + +Not all watchdog drivers will support a pretimeout. + +Environmental monitoring: All watchdog drivers are required return more information about the system, some do temperature, fan and power level monitoring, some can tell you @@ -169,6 +193,10 @@ The watchdog saw a keepalive ping since it was last queried. WDIOF_SETTIMEOUT Can set/get the timeout +The watchdog can do pretimeouts. + + WDIOF_PRETIMEOUT Pretimeout (in seconds), get/set + For those drivers that return any bits set in the option field, the GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h index 1192ed8f4fe8..a99c937f665e 100644 --- a/include/linux/watchdog.h +++ b/include/linux/watchdog.h @@ -28,6 +28,8 @@ struct watchdog_info { #define WDIOC_KEEPALIVE _IOR(WATCHDOG_IOCTL_BASE, 5, int) #define WDIOC_SETTIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 6, int) #define WDIOC_GETTIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 7, int) +#define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int) +#define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int) #define WDIOF_UNKNOWN -1 /* Unknown flag error */ #define WDIOS_UNKNOWN -1 /* Unknown status error */ @@ -41,6 +43,7 @@ struct watchdog_info { #define WDIOF_POWEROVER 0x0040 /* Power over voltage */ #define WDIOF_SETTIMEOUT 0x0080 /* Set timeout (in seconds) */ #define WDIOF_MAGICCLOSE 0x0100 /* Supports magic close char */ +#define WDIOF_PRETIMEOUT 0x0200 /* Pretimeout (in seconds), get/set */ #define WDIOF_KEEPALIVEPING 0x8000 /* Keep alive ping reply */ #define WDIOS_DISABLECARD 0x0001 /* Turn off the watchdog timer */ From 58b519f3e5e491d5a3e320dc525f58ac439bdde4 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Sun, 21 May 2006 12:48:44 +0200 Subject: [PATCH 023/556] [WATCHDOG] add WDIOC_GETTIMELEFT ioctl Some watchdog drivers have the ability to report the remaining time before the system will reboot. With the WDIOC_GETTIMELEFT ioctl you can now read the time left before the watchdog would reboot your system. The following drivers support this new IOCTL: i8xx_tco.c, pcwd_pci.c and pcwd_usb.c . Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- Documentation/watchdog/watchdog-api.txt | 9 ++++++++ drivers/char/watchdog/i8xx_tco.c | 28 ++++++++++++++++++++++- drivers/char/watchdog/pcwd_pci.c | 30 ++++++++++++++++++++++++- drivers/char/watchdog/pcwd_usb.c | 23 +++++++++++++++++++ include/linux/watchdog.h | 7 +++--- 5 files changed, 92 insertions(+), 5 deletions(-) diff --git a/Documentation/watchdog/watchdog-api.txt b/Documentation/watchdog/watchdog-api.txt index 7dc2c1c6f779..d738ec25eaa4 100644 --- a/Documentation/watchdog/watchdog-api.txt +++ b/Documentation/watchdog/watchdog-api.txt @@ -134,6 +134,15 @@ There is also a get function for getting the pretimeout: Not all watchdog drivers will support a pretimeout. +Get the number of seconds before reboot: + +Some watchdog drivers have the ability to report the remaining time +before the system will reboot. The WDIOC_GETTIMELEFT is the ioctl +that returns the number of seconds before reboot. + + ioctl(fd, WDIOC_GETTIMELEFT, &timeleft); + printf("The timeout was is %d seconds\n", timeleft); + Environmental monitoring: All watchdog drivers are required return more information about the system, diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c index fa2ba9ebe42a..bfbdbbf3c2f2 100644 --- a/drivers/char/watchdog/i8xx_tco.c +++ b/drivers/char/watchdog/i8xx_tco.c @@ -205,6 +205,23 @@ static int tco_timer_set_heartbeat (int t) return 0; } +static int tco_timer_get_timeleft (int *time_left) +{ + unsigned char val; + + spin_lock(&tco_lock); + + /* read the TCO Timer */ + val = inb (TCO1_RLD); + val &= 0x3f; + + spin_unlock(&tco_lock); + + *time_left = (int)((val * 6) / 10); + + return 0; +} + /* * /dev/watchdog handling */ @@ -272,6 +289,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file, { int new_options, retval = -EINVAL; int new_heartbeat; + int time_left; void __user *argp = (void __user *)arg; int __user *p = argp; static struct watchdog_info ident = { @@ -320,7 +338,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file, return -EFAULT; if (tco_timer_set_heartbeat(new_heartbeat)) - return -EINVAL; + return -EINVAL; tco_timer_keepalive (); /* Fall */ @@ -329,6 +347,14 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file, case WDIOC_GETTIMEOUT: return put_user(heartbeat, p); + case WDIOC_GETTIMELEFT: + { + if (tco_timer_get_timeleft(&time_left)) + return -EINVAL; + + return put_user(time_left, p); + } + default: return -ENOIOCTLCMD; } diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c index 2451edbefece..1f40ecefbf72 100644 --- a/drivers/char/watchdog/pcwd_pci.c +++ b/drivers/char/watchdog/pcwd_pci.c @@ -21,7 +21,7 @@ */ /* - * A bells and whistles driver is available from: + * A bells and whistles driver is available from: * http://www.kernel.org/pub/linux/kernel/people/wim/pcwd/pcwd_pci/ * * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ @@ -390,6 +390,24 @@ static int pcipcwd_get_temperature(int *temperature) return 0; } +static int pcipcwd_get_timeleft(int *time_left) +{ + int msb; + int lsb; + + /* Read the time that's left before rebooting */ + /* Note: if the board is not yet armed then we will read 0xFFFF */ + send_command(CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb); + + *time_left = (msb << 8) + lsb; + + if (debug >= VERBOSE) + printk(KERN_DEBUG PFX "Time left before next reboot: %d\n", + *time_left); + + return 0; +} + /* * /dev/watchdog handling */ @@ -512,6 +530,16 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file, case WDIOC_GETTIMEOUT: return put_user(heartbeat, p); + case WDIOC_GETTIMELEFT: + { + int time_left; + + if (pcipcwd_get_timeleft(&time_left)) + return -EFAULT; + + return put_user(time_left, p); + } + default: return -ENOIOCTLCMD; } diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index 3fdfda9324fa..0d072bed501d 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c @@ -317,6 +317,19 @@ static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd, int *temp return 0; } +static int usb_pcwd_get_timeleft(struct usb_pcwd_private *usb_pcwd, int *time_left) +{ + unsigned char msb, lsb; + + /* Read the time that's left before rebooting */ + /* Note: if the board is not yet armed then we will read 0xFFFF */ + usb_pcwd_send_command(usb_pcwd, CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb); + + *time_left = (msb << 8) + lsb; + + return 0; +} + /* * /dev/watchdog handling */ @@ -422,6 +435,16 @@ static int usb_pcwd_ioctl(struct inode *inode, struct file *file, case WDIOC_GETTIMEOUT: return put_user(heartbeat, p); + case WDIOC_GETTIMELEFT: + { + int time_left; + + if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left)) + return -EFAULT; + + return put_user(time_left, p); + } + default: return -ENOIOCTLCMD; } diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h index a99c937f665e..011bcfeb9f09 100644 --- a/include/linux/watchdog.h +++ b/include/linux/watchdog.h @@ -30,6 +30,7 @@ struct watchdog_info { #define WDIOC_GETTIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 7, int) #define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int) #define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int) +#define WDIOC_GETTIMELEFT _IOR(WATCHDOG_IOCTL_BASE, 10, int) #define WDIOF_UNKNOWN -1 /* Unknown flag error */ #define WDIOS_UNKNOWN -1 /* Unknown status error */ @@ -40,9 +41,9 @@ struct watchdog_info { #define WDIOF_EXTERN2 0x0008 /* External relay 2 */ #define WDIOF_POWERUNDER 0x0010 /* Power bad/power fault */ #define WDIOF_CARDRESET 0x0020 /* Card previously reset the CPU */ -#define WDIOF_POWEROVER 0x0040 /* Power over voltage */ -#define WDIOF_SETTIMEOUT 0x0080 /* Set timeout (in seconds) */ -#define WDIOF_MAGICCLOSE 0x0100 /* Supports magic close char */ +#define WDIOF_POWEROVER 0x0040 /* Power over voltage */ +#define WDIOF_SETTIMEOUT 0x0080 /* Set timeout (in seconds) */ +#define WDIOF_MAGICCLOSE 0x0100 /* Supports magic close char */ #define WDIOF_PRETIMEOUT 0x0200 /* Pretimeout (in seconds), get/set */ #define WDIOF_KEEPALIVEPING 0x8000 /* Keep alive ping reply */ From dfc7bd9c385a888851a2d009ba272099549f98cc Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Sun, 21 May 2006 15:32:59 +0200 Subject: [PATCH 024/556] [WATCHDOG] convert AT91RM9200 watchdog to platform driver Converted to a platform driver. Added suspend/resume support - the watchdog is disabled during the sleep states. Original patch from David Brownell. Signed-off-by: Andrew Victor Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/at91_wdt.c | 82 +++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91_wdt.c index ac83bc4b019a..00080655533d 100644 --- a/drivers/char/watchdog/at91_wdt.c +++ b/drivers/char/watchdog/at91_wdt.c @@ -17,14 +17,15 @@ #include #include #include +#include #include #include #include #include -#define WDT_DEFAULT_TIME 5 /* 5 seconds */ -#define WDT_MAX_TIME 256 /* 256 seconds */ +#define WDT_DEFAULT_TIME 5 /* seconds */ +#define WDT_MAX_TIME 256 /* seconds */ static int wdt_time = WDT_DEFAULT_TIME; static int nowayout = WATCHDOG_NOWAYOUT; @@ -32,8 +33,10 @@ static int nowayout = WATCHDOG_NOWAYOUT; module_param(wdt_time, int, 0); MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); +#ifdef CONFIG_WATCHDOG_NOWAYOUT module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +#endif static unsigned long at91wdt_busy; @@ -138,7 +141,7 @@ static int at91_wdt_ioctl(struct inode *inode, struct file *file, case WDIOC_SETTIMEOUT: if (get_user(new_value, p)) return -EFAULT; - + if (at91_wdt_settimeout(new_value)) return -EINVAL; @@ -196,27 +199,84 @@ static struct miscdevice at91wdt_miscdev = { .fops = &at91wdt_fops, }; -static int __init at91_wdt_init(void) +static int __init at91wdt_probe(struct platform_device *pdev) { int res; - /* Check that the heartbeat value is within range; if not reset to the default */ - if (at91_wdt_settimeout(wdt_time)) { - at91_wdt_settimeout(WDT_DEFAULT_TIME); - printk(KERN_INFO "at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time); - } + if (at91wdt_miscdev.dev) + return -EBUSY; + at91wdt_miscdev.dev = &pdev->dev; res = misc_register(&at91wdt_miscdev); if (res) return res; - printk("AT91 Watchdog Timer enabled (%d seconds, nowayout=%d)\n", wdt_time, nowayout); + printk("AT91 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : ""); return 0; } +static int __exit at91wdt_remove(struct platform_device *pdev) +{ + int res; + + res = misc_deregister(&at91wdt_miscdev); + if (!res) + at91wdt_miscdev.dev = NULL; + + return res; +} + +static void at91wdt_shutdown(struct platform_device *pdev) +{ + at91_wdt_stop(); +} + +#ifdef CONFIG_PM + +static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message) +{ + at91_wdt_stop(); + return 0; +} + +static int at91wdt_resume(struct platform_device *pdev) +{ + if (at91wdt_busy) + at91_wdt_start(); + return 0; +} + +#else +#define at91wdt_suspend NULL +#define at91wdt_resume NULL +#endif + +static struct platform_driver at91wdt_driver = { + .probe = at91wdt_probe, + .remove = __exit_p(at91wdt_remove), + .shutdown = at91wdt_shutdown, + .suspend = at91wdt_suspend, + .resume = at91wdt_resume, + .driver = { + .name = "at91_wdt", + .owner = THIS_MODULE, + }, +}; + +static int __init at91_wdt_init(void) +{ + /* Check that the heartbeat value is within range; if not reset to the default */ + if (at91_wdt_settimeout(wdt_time)) { + at91_wdt_settimeout(WDT_DEFAULT_TIME); + pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time); + } + + return platform_driver_register(&at91wdt_driver); +} + static void __exit at91_wdt_exit(void) { - misc_deregister(&at91wdt_miscdev); + platform_driver_unregister(&at91wdt_driver); } module_init(at91_wdt_init); From 0d420f9d6111b3a2fb7d5dd0180456eed469055d Mon Sep 17 00:00:00 2001 From: Savin Zlobec Date: Wed, 21 Jun 2006 11:51:20 +0200 Subject: [PATCH 025/556] [MTD] NAND: Missing fixups The oob fixups broke a return value and missed one patch from the Mailing List. Signed-off-by: Savin Zlobec Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 27083ed0a017..8df184f6d8d1 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1176,7 +1176,7 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, status = chip->waitfunc(mtd, chip); - return status; + return status & NAND_STATUS_FAIL ? -EIO : 0; } /** @@ -1271,10 +1271,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); buf = nand_transfer_oob(chip, buf, ops); - readlen -= ops->ooblen; - if (!readlen) - break; - if (!(chip->options & NAND_NO_READRDY)) { /* * Apply delay or wait for ready/busy pin. Do this @@ -1288,6 +1284,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, nand_wait_ready(mtd); } + readlen -= ops->ooblen; + if (!readlen) + break; + /* Increment page address */ realpage++; From 99974c62b6acd4093b6f485132067089c39f967c Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 21 Jun 2006 15:43:05 +0100 Subject: [PATCH 026/556] [MTD] NAND: S3C2410 convert prinks to dev_*()s Convert the use of printk() to the correct dev_info/dev_err functions Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/s3c2410.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 2c262fe03d8a..5219bd212cf6 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -63,8 +63,6 @@ #include #include -#define PFX "s3c2410-nand: " - #ifdef CONFIG_MTD_NAND_S3C2410_HWECC static int hardware_ecc = 1; #else @@ -195,11 +193,11 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_d } if (tacls < 0 || twrph0 < 0 || twrph1 < 0) { - printk(KERN_ERR PFX "cannot get timings suitable for board\n"); + dev_err(info->device, "cannot get suitable timings\n"); return -EINVAL; } - printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", + dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); if (!info->is_s3c2440) { @@ -218,7 +216,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_d info->regs + S3C2440_NFCONT); } - pr_debug(PFX "NF_CONF is 0x%lx\n", cfg); + dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); writel(cfg, info->regs + S3C2410_NFCONF); return 0; @@ -250,7 +248,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) cur |= bit; } else { if (nmtd->set != NULL && chip > nmtd->set->nr_chips) { - printk(KERN_ERR PFX "chip %d out of range\n", chip); + dev_err(info->device, "invalid chip %d\n", chip); return; } From b3818ed446fc41db41b5a38d934ac2b69fd2e0aa Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 21 Jun 2006 13:10:26 -0400 Subject: [PATCH 027/556] [AGPGART] Compile fix for ati-agp Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/char/agp/ati-agp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 34bbd41f062a..d712078ed822 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -248,14 +248,14 @@ static int ati_configure(void) static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state) { pci_save_state(dev); - pci_set_power_state (pdev, 3); + pci_set_power_state(dev, 3); return 0; } static int agp_ati_resume(struct pci_dev *dev) { - pci_set_power_state (pdev, 0); + pci_set_power_state(dev, 0); pci_restore_state(dev); return ati_configure(); From 4092e256ca35e62b431ebad4e0c42c6360acee08 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 21 Jun 2006 17:36:24 -0400 Subject: [PATCH 028/556] [AGPGART] Fix pci_register_driver checking in amd64-agp pci_register_driver() never returns a positive number. Signed-off-by: Dave Jones --- drivers/char/agp/amd64-agp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index ac3c33a2e37d..e449d949f7ea 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -761,7 +761,7 @@ int __init agp_amd64_init(void) if (agp_off) return -EINVAL; - if (pci_register_driver(&agp_amd64_pci_driver) > 0) { + if (pci_register_driver(&agp_amd64_pci_driver) < 0) { struct pci_dev *dev; if (!agp_try_unsupported && !agp_try_unsupported_boot) { printk(KERN_INFO PFX "No supported AGP bridge found.\n"); From 1794c13002918c2216e2e11913eb299d071a5731 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 22 Jun 2006 13:06:43 +0200 Subject: [PATCH 029/556] [MTD] NAND: ndfc fix address offset thinko The rework of the command handling in the nand driver led to wrong address setting in the command control function. Use the correct address again. Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/ndfc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index fe8d38514ba6..e5bd88f2d560 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -61,15 +61,15 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { - struct nand_chip *chip = mtd->priv; + struct ndfc_controller *ndfc = &ndfc_ctrl; if (cmd == NAND_CMD_NONE) return; if (ctrl & NAND_CLE) - writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_CMD); + writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD); else - writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_ALE); + writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE); } static int ndfc_ready(struct mtd_info *mtd) From 17ffc7ba6d7ea68b8d5f55a5ca1b87163e69720d Mon Sep 17 00:00:00 2001 From: "Artem B. Bityutskiy" Date: Thu, 22 Jun 2006 18:15:48 +0400 Subject: [PATCH 030/556] [MTD] Initialize 'writesize' Signed-off-by: Artem B. Bityutskiy --- drivers/mtd/chips/cfi_cmdset_0001.c | 1 + drivers/mtd/chips/jedec.c | 1 + drivers/mtd/chips/map_absent.c | 3 ++- drivers/mtd/chips/map_ram.c | 1 + drivers/mtd/chips/map_rom.c | 1 + drivers/mtd/devices/block2mtd.c | 1 + drivers/mtd/devices/ms02-nv.c | 1 + drivers/mtd/devices/mtd_dataflash.c | 1 + drivers/mtd/devices/phram.c | 1 + drivers/mtd/devices/pmc551.c | 3 ++- drivers/mtd/devices/slram.c | 1 + 11 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 0d435814aaa1..39edb8250fbc 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -357,6 +357,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) mtd->resume = cfi_intelext_resume; mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; + mtd->writesize = 1; mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c index c40b48dabed3..2c3f019197c1 100644 --- a/drivers/mtd/chips/jedec.c +++ b/drivers/mtd/chips/jedec.c @@ -256,6 +256,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) MTD->name = map->name; MTD->type = MTD_NORFLASH; MTD->flags = MTD_CAP_NORFLASH; + MTD->writesize = 1; MTD->erasesize = SectorSize*(map->buswidth); // printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize); MTD->size = priv->size; diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c index a611de9b1515..ac01a949b687 100644 --- a/drivers/mtd/chips/map_absent.c +++ b/drivers/mtd/chips/map_absent.c @@ -64,7 +64,8 @@ static struct mtd_info *map_absent_probe(struct map_info *map) mtd->write = map_absent_write; mtd->sync = map_absent_sync; mtd->flags = 0; - mtd->erasesize = PAGE_SIZE; + mtd->erasesize = PAGE_SIZE; + mtd->writesize = 1; __module_get(THIS_MODULE); return mtd; diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c index 763925747db6..3a66680abfd0 100644 --- a/drivers/mtd/chips/map_ram.c +++ b/drivers/mtd/chips/map_ram.c @@ -71,6 +71,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map) mtd->write = mapram_write; mtd->sync = mapram_nop; mtd->flags = MTD_CAP_RAM; + mtd->writesize = 1; mtd->erasesize = PAGE_SIZE; while(mtd->size & (mtd->erasesize - 1)) diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c index bc6ee9ef8a31..1b328b1378fd 100644 --- a/drivers/mtd/chips/map_rom.c +++ b/drivers/mtd/chips/map_rom.c @@ -47,6 +47,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map) mtd->sync = maprom_nop; mtd->flags = MTD_CAP_ROM; mtd->erasesize = map->size; + mtd->writesize = 1; __module_get(THIS_MODULE); return mtd; diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 0d98c223c5fc..be3f1c136d02 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -324,6 +324,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; dev->mtd.erasesize = erase_size; + dev->mtd.writesize = 1; dev->mtd.type = MTD_RAM; dev->mtd.flags = MTD_CAP_RAM; dev->mtd.erase = block2mtd_erase; diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index 4ab7670770e4..08dfb899b272 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c @@ -225,6 +225,7 @@ static int __init ms02nv_init_one(ulong addr) mtd->owner = THIS_MODULE; mtd->read = ms02nv_read; mtd->write = ms02nv_write; + mtd->writesize = 1; ret = -EIO; if (add_mtd_device(mtd)) { diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index a19480d07888..04271d02b6b6 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -478,6 +478,7 @@ add_dataflash(struct spi_device *spi, char *name, device->name = (pdata && pdata->name) ? pdata->name : priv->name; device->size = nr_pages * pagesize; device->erasesize = pagesize; + device->writesize = pagesize; device->owner = THIS_MODULE; device->type = MTD_DATAFLASH; device->flags = MTD_CAP_NORFLASH; diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index e09e416667d3..6c7337f9ebbb 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -151,6 +151,7 @@ static int register_device(char *name, unsigned long start, unsigned long len) new->mtd.owner = THIS_MODULE; new->mtd.type = MTD_RAM; new->mtd.erasesize = PAGE_SIZE; + new->mtd.writesize = 1; ret = -EAGAIN; if (add_mtd_device(&new->mtd)) { diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index 666cce1bf60c..f620d74f1004 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -778,7 +778,8 @@ static int __init init_pmc551(void) mtd->type = MTD_RAM; mtd->name = "PMC551 RAM board"; mtd->erasesize = 0x10000; - mtd->owner = THIS_MODULE; + mtd->writesize = 1; + mtd->owner = THIS_MODULE; if (add_mtd_device(mtd)) { printk(KERN_NOTICE "pmc551: Failed to register new device\n"); diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index b3f665e3c38b..542a0c009006 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -209,6 +209,7 @@ static int register_device(char *name, unsigned long start, unsigned long length (*curmtd)->mtdinfo->owner = THIS_MODULE; (*curmtd)->mtdinfo->type = MTD_RAM; (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ; + (*curmtd)->mtdinfo->writesize = 1; if (add_mtd_device((*curmtd)->mtdinfo)) { E("slram: Failed to register new device\n"); From 189acaaef81b1d71aedd0d28810de24160c2e781 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 Jun 2006 02:33:48 +0000 Subject: [PATCH 031/556] [CIFS] Enable sec flags on mount for cifs (part one) Signed-off-by: Steve French --- fs/cifs/README | 2 + fs/cifs/cifsproto.h | 2 +- fs/cifs/connect.c | 338 +++----------------------------------------- fs/cifs/sess.c | 7 +- 4 files changed, 28 insertions(+), 321 deletions(-) diff --git a/fs/cifs/README b/fs/cifs/README index a68f8e3db2d2..46c2cfa5acf3 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -453,6 +453,8 @@ sec Security mode. Allowed values are: server requires signing also can be the default) ntlmv2 Use NTLMv2 password hashing ntlmv2i Use NTLMv2 password hashing with packet signing + lanman (if configured in kernel config) use older + lanman hash The mount.cifs mount helper also accepts a few mount options before -o including: diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7ffd5b0d63cf..7ed06bfa1921 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -68,10 +68,10 @@ extern void header_assemble(struct smb_hdr *, char /* command */ , extern int small_smb_init_no_tc(const int smb_cmd, const int wct, struct cifsSesInfo *ses, void ** request_buf); +#endif extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int stage, const struct nls_table *nls_cp); -#endif extern __u16 GetNextMid(struct TCP_Server_Info *server); extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index faaf9eb15b9f..01608bb4d673 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -68,6 +68,7 @@ struct smb_vol { gid_t linux_gid; mode_t file_mode; mode_t dir_mode; + unsigned secFlg; unsigned rw:1; unsigned retry:1; unsigned intr:1; @@ -81,12 +82,7 @@ struct smb_vol { unsigned remap:1; /* set to remap seven reserved chars in filenames */ unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ unsigned sfu_emul:1; - unsigned krb5:1; - unsigned ntlm:1; - unsigned ntlmv2:1; unsigned nullauth:1; /* attempt to authenticate with null user */ - unsigned sign:1; - unsigned seal:1; /* encrypt */ unsigned nocase; /* request case insensitive filenames */ unsigned nobrl; /* disable sending byte range locks to srv */ unsigned int rsize; @@ -789,7 +785,6 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ vol->rw = TRUE; - vol->ntlm = TRUE; /* default is always to request posix paths. */ vol->posix_paths = 1; @@ -920,30 +915,35 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) cERROR(1,("no security value specified")); continue; } else if (strnicmp(value, "krb5i", 5) == 0) { - vol->sign = 1; - vol->krb5 = 1; + vol->secFlg = CIFSSEC_MAY_KRB5 | + CIFSSEC_MUST_SIGN; } else if (strnicmp(value, "krb5p", 5) == 0) { - /* vol->seal = 1; - vol->krb5 = 1; */ + /* vol->secFlg = CIFSSEC_MUST_SEAL | + CIFSSEC_MAY_KRB5; */ cERROR(1,("Krb5 cifs privacy not supported")); return 1; } else if (strnicmp(value, "krb5", 4) == 0) { - vol->krb5 = 1; + vol->secFlg = CIFSSEC_MAY_KRB5; } else if (strnicmp(value, "ntlmv2i", 7) == 0) { - vol->ntlmv2 = 1; - vol->sign = 1; + vol->secFlg = CIFSSEC_MAY_NTLMV2 | + CIFSSEC_MUST_SIGN; } else if (strnicmp(value, "ntlmv2", 6) == 0) { - vol->ntlmv2 = 1; + vol->secFlg = CIFSSEC_MAY_NTLMV2; } else if (strnicmp(value, "ntlmi", 5) == 0) { - vol->ntlm = 1; - vol->sign = 1; + vol->secFlg = CIFSSEC_MAY_NTLM | + CIFSSEC_MUST_SIGN; } else if (strnicmp(value, "ntlm", 4) == 0) { /* ntlm is default so can be turned off too */ - vol->ntlm = 1; + vol->secFlg = CIFSSEC_MAY_NTLM; } else if (strnicmp(value, "nontlm", 6) == 0) { - vol->ntlm = 0; + /* BB is there a better way to do this? */ + vol->secFlg = CIFSSEC_MAY_NTLMV2; +#ifdef CONFIG_CIFS_WEAK_PW_HASH + } else if (strnicmp(value, "lanman", 6) == 0) { + vol->secFlg = CIFSSEC_MAY_LANMAN; +#endif } else if (strnicmp(value, "none", 4) == 0) { - vol->nullauth = 1; + vol->nullauth = 1; } else { cERROR(1,("bad security option: %s", value)); return 1; @@ -1777,6 +1777,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, } pSesInfo->linux_uid = volume_info.linux_uid; down(&pSesInfo->sesSem); + /* BB FIXME need to pass vol->secFlgs BB */ rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); up(&pSesInfo->sesSem); if(!rc) @@ -2283,292 +2284,6 @@ sesssetup_nomem: /* do not return an error on nomem for the info strings, return rc; } -static int -CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *SecurityBlob,int SecurityBlobLength, - const struct nls_table *nls_codepage) -{ - struct smb_hdr *smb_buffer; - struct smb_hdr *smb_buffer_response; - SESSION_SETUP_ANDX *pSMB; - SESSION_SETUP_ANDX *pSMBr; - char *bcc_ptr; - char *user; - char *domain; - int rc = 0; - int remaining_words = 0; - int bytes_returned = 0; - int len; - __u32 capabilities; - __u16 count; - - cFYI(1, ("In spnego sesssetup ")); - if(ses == NULL) - return -EINVAL; - user = ses->userName; - domain = ses->domainName; - - smb_buffer = cifs_buf_get(); - if (smb_buffer == NULL) { - return -ENOMEM; - } - smb_buffer_response = smb_buffer; - pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; - - /* send SMBsessionSetup here */ - header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, - NULL /* no tCon exists yet */ , 12 /* wct */ ); - - smb_buffer->Mid = GetNextMid(ses->server); - pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; - pSMB->req.AndXCommand = 0xFF; - if(ses->server->maxBuf > 64*1024) - ses->server->maxBuf = (64*1023); - pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); - pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); - - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - - capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | - CAP_EXTENDED_SECURITY; - if (ses->capabilities & CAP_UNICODE) { - smb_buffer->Flags2 |= SMBFLG2_UNICODE; - capabilities |= CAP_UNICODE; - } - if (ses->capabilities & CAP_STATUS32) { - smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; - capabilities |= CAP_STATUS32; - } - if (ses->capabilities & CAP_DFS) { - smb_buffer->Flags2 |= SMBFLG2_DFS; - capabilities |= CAP_DFS; - } - pSMB->req.Capabilities = cpu_to_le32(capabilities); - - pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); - bcc_ptr = pByteArea(smb_buffer); - memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength); - bcc_ptr += SecurityBlobLength; - - if (ses->capabilities & CAP_UNICODE) { - if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */ - *bcc_ptr = 0; - bcc_ptr++; - } - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage); - bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */ - bcc_ptr += 2; /* trailing null */ - if (domain == NULL) - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, - "CIFS_LINUX_DOM", 32, nls_codepage); - else - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, - nls_codepage); - bcc_ptr += 2 * bytes_returned; - bcc_ptr += 2; - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", - 32, nls_codepage); - bcc_ptr += 2 * bytes_returned; - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, - nls_codepage); - bcc_ptr += 2 * bytes_returned; - bcc_ptr += 2; - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, - 64, nls_codepage); - bcc_ptr += 2 * bytes_returned; - bcc_ptr += 2; - } else { - strncpy(bcc_ptr, user, 200); - bcc_ptr += strnlen(user, 200); - *bcc_ptr = 0; - bcc_ptr++; - if (domain == NULL) { - strcpy(bcc_ptr, "CIFS_LINUX_DOM"); - bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; - } else { - strncpy(bcc_ptr, domain, 64); - bcc_ptr += strnlen(domain, 64); - *bcc_ptr = 0; - bcc_ptr++; - } - strcpy(bcc_ptr, "Linux version "); - bcc_ptr += strlen("Linux version "); - strcpy(bcc_ptr, system_utsname.release); - bcc_ptr += strlen(system_utsname.release) + 1; - strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); - bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; - } - count = (long) bcc_ptr - (long) pByteArea(smb_buffer); - smb_buffer->smb_buf_length += count; - pSMB->req.ByteCount = cpu_to_le16(count); - - 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)) { - __u16 action = le16_to_cpu(pSMBr->resp.Action); - __u16 blob_len = - le16_to_cpu(pSMBr->resp.SecurityBlobLength); - if (action & GUEST_LOGIN) - cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ - if (ses) { - ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ - cFYI(1, ("UID = %d ", ses->Suid)); - bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */ - - /* BB Fix below to make endian neutral !! */ - - if ((pSMBr->resp.hdr.WordCount == 3) - || ((pSMBr->resp.hdr.WordCount == 4) - && (blob_len < - pSMBr->resp.ByteCount))) { - if (pSMBr->resp.hdr.WordCount == 4) { - bcc_ptr += - blob_len; - cFYI(1, - ("Security Blob Length %d ", - blob_len)); - } - - if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { - if ((long) (bcc_ptr) % 2) { - remaining_words = - (BCC(smb_buffer_response) - - 1) / 2; - bcc_ptr++; /* Unicode strings must be word aligned */ - } else { - remaining_words = - BCC - (smb_buffer_response) / 2; - } - 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 */ - if(ses->serverOS) - kfree(ses->serverOS); - ses->serverOS = - kzalloc(2 * (len + 1), GFP_KERNEL); - cifs_strfromUCS_le(ses->serverOS, - (__le16 *) - bcc_ptr, len, - nls_codepage); - bcc_ptr += 2 * (len + 1); - remaining_words -= len + 1; - ses->serverOS[2 * len] = 0; - ses->serverOS[1 + (2 * len)] = 0; - if (remaining_words > 0) { - len = UniStrnlen((wchar_t *)bcc_ptr, - remaining_words - - 1); - if(ses->serverNOS) - kfree(ses->serverNOS); - ses->serverNOS = - kzalloc(2 * (len + 1), - GFP_KERNEL); - cifs_strfromUCS_le(ses->serverNOS, - (__le16 *)bcc_ptr, - len, - nls_codepage); - bcc_ptr += 2 * (len + 1); - ses->serverNOS[2 * len] = 0; - ses->serverNOS[1 + (2 * len)] = 0; - remaining_words -= len + 1; - if (remaining_words > 0) { - len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); - /* last string not null terminated (e.g.Windows XP/2000) */ - if(ses->serverDomain) - kfree(ses->serverDomain); - ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL); - cifs_strfromUCS_le(ses->serverDomain, - (__le16 *)bcc_ptr, - len, nls_codepage); - bcc_ptr += 2*(len+1); - ses->serverDomain[2*len] = 0; - ses->serverDomain[1+(2*len)] = 0; - } /* else no more room so create dummy domain string */ - else { - if(ses->serverDomain) - kfree(ses->serverDomain); - ses->serverDomain = - kzalloc(2,GFP_KERNEL); - } - } else {/* no room use dummy domain&NOS */ - if(ses->serverDomain) - kfree(ses->serverDomain); - ses->serverDomain = kzalloc(2, GFP_KERNEL); - if(ses->serverNOS) - kfree(ses->serverNOS); - ses->serverNOS = kzalloc(2, GFP_KERNEL); - } - } else { /* ASCII */ - - len = strnlen(bcc_ptr, 1024); - if (((long) bcc_ptr + len) - (long) - pByteArea(smb_buffer_response) - <= BCC(smb_buffer_response)) { - if(ses->serverOS) - kfree(ses->serverOS); - ses->serverOS = kzalloc(len + 1, GFP_KERNEL); - strncpy(ses->serverOS, bcc_ptr, len); - - bcc_ptr += len; - bcc_ptr[0] = 0; /* null terminate the string */ - bcc_ptr++; - - len = strnlen(bcc_ptr, 1024); - if(ses->serverNOS) - kfree(ses->serverNOS); - ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); - strncpy(ses->serverNOS, bcc_ptr, len); - bcc_ptr += len; - bcc_ptr[0] = 0; - bcc_ptr++; - - len = strnlen(bcc_ptr, 1024); - if(ses->serverDomain) - kfree(ses->serverDomain); - ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); - strncpy(ses->serverDomain, bcc_ptr, len); - bcc_ptr += len; - bcc_ptr[0] = 0; - bcc_ptr++; - } else - cFYI(1, - ("Variable field of length %d extends beyond end of smb ", - len)); - } - } else { - cERROR(1, - (" Security Blob Length extends beyond end of SMB")); - } - } else { - cERROR(1, ("No session structure passed in.")); - } - } else { - cERROR(1, - (" Invalid Word count %d: ", - smb_buffer_response->WordCount)); - rc = -EIO; - } - - if (smb_buffer) - cifs_buf_release(smb_buffer); - - return rc; -} - static int CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, struct cifsSesInfo *ses, int * pNTLMv2_flag, @@ -3550,20 +3265,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, pSesInfo->server->secMode, pSesInfo->server->capabilities, pSesInfo->server->timeZone)); -#ifdef CONFIG_CIFS_EXPERIMENTAL - if(experimEnabled > 1) + if(experimEnabled < 2) rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); - else -#endif - if (extended_security + else if (extended_security && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) && (pSesInfo->server->secType == NTLMSSP)) { - cFYI(1, ("New style sesssetup")); - rc = CIFSSpnegoSessSetup(xid, pSesInfo, - NULL /* security blob */, - 0 /* blob length */, - nls_info); + rc = -EOPNOTSUPP; } else if (extended_security && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) && (pSesInfo->server->secType == RawNTLMSSP)) { diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c039b54206aa..70e32a81c213 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -33,8 +33,6 @@ extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); -#ifdef CONFIG_CIFS_EXPERIMENTAL - static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) { __u32 capabilities = 0; @@ -319,7 +317,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, __u32 capabilities; int count; int resp_buf_type = 0; - struct kvec iov[1]; + struct kvec iov[2]; /* BB split variable length info into 2nd iovec */ enum securityEnum type; __u16 action; int bytes_remaining; @@ -489,7 +487,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, } action = le16_to_cpu(pSMB->resp.Action); if (action & GUEST_LOGIN) - cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */ + cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */ ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ cFYI(1, ("UID = %d ", ses->Suid)); /* response can have either 3 or 4 word count - Samba sends 3 */ @@ -525,4 +523,3 @@ ssetup_exit: return rc; } -#endif /* CONFIG_CIFS_EXPERIMENTAL */ From 4280370efe0e9c527ccd6188d6211a10bcb22b1e Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 23 Jun 2006 12:55:46 +0200 Subject: [PATCH 032/556] [AGPGART] remove unused variable This patch removes an unused variable. Signed-off-by: Adrian Bunk Signed-off-by: Dave Jones --- drivers/char/agp/nvidia-agp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index b3a53e7f3602..df7f37b2739a 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -387,8 +387,6 @@ static int agp_nvidia_suspend(struct pci_dev *pdev, pm_message_t state) static int agp_nvidia_resume(struct pci_dev *pdev) { - struct agp_bridge_data *bridge = pci_get_drvdata(pdev); - /* set power state 0 and restore PCI space */ pci_set_power_state (pdev, 0); pci_restore_state(pdev); From f90f00a358fe887fe5c3454897521064bdace7cc Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 25 Jun 2006 15:59:32 +0000 Subject: [PATCH 033/556] [CIFS] Fix compile warning when CONFIG_CIFS_EXPERIMENTAL is off Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 2 -- fs/cifs/cifssmb.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7ed06bfa1921..a5ddc62d6fe6 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -64,11 +64,9 @@ extern int map_smb_to_linux_error(struct smb_hdr *smb); extern void header_assemble(struct smb_hdr *, char /* command */ , const struct cifsTconInfo *, int /* length of fixed section (word count) in two byte units */); -#ifdef CONFIG_CIFS_EXPERIMENTAL extern int small_smb_init_no_tc(const int smb_cmd, const int wct, struct cifsSesInfo *ses, void ** request_buf); -#endif extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int stage, const struct nls_table *nls_cp); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 271a037a386f..38f83db20764 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -209,7 +209,6 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL int small_smb_init_no_tc(const int smb_command, const int wct, struct cifsSesInfo *ses, void **request_buf) @@ -235,7 +234,6 @@ small_smb_init_no_tc(const int smb_command, const int wct, return rc; } -#endif /* CONFIG_CIFS_EXPERIMENTAL */ /* If the return code is zero, this function must fill in request_buf pointer */ static int From cd49b492fe3fef0b6348f18001f0d73f2577eb01 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 26 Jun 2006 04:22:36 +0000 Subject: [PATCH 034/556] [CIFS] remove some redundant null pointer checks some of them pointed out by Dave Jones Signed-off-by: Steve French --- fs/cifs/connect.c | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 01608bb4d673..c0f98ddea88c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2173,8 +2173,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (remaining_words > 0) { len = UniStrnlen((wchar_t *)bcc_ptr, remaining_words-1); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL); if(ses->serverNOS == NULL) goto sesssetup_nomem; @@ -2214,12 +2213,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* if these kcallocs fail not much we can do, but better to not fail the sesssetup itself */ - if(ses->serverDomain) - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } @@ -2228,8 +2225,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - if(ses->serverOS) - kfree(ses->serverOS); + kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1,GFP_KERNEL); if(ses->serverOS == NULL) goto sesssetup_nomem; @@ -2240,8 +2236,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); if(ses->serverNOS == NULL) goto sesssetup_nomem; @@ -2508,8 +2503,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, bcc_ptr, remaining_words - 1); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1), GFP_KERNEL); @@ -2527,8 +2521,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ - if(ses->serverDomain) - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2 * (len + @@ -2547,19 +2540,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, = 0; } /* else no more room so create dummy domain string */ else { - if(ses->serverDomain) - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); } } else { /* no room so create dummy domain and NOS string */ - if(ses->serverDomain); - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } @@ -2581,8 +2571,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); @@ -2592,8 +2581,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - if(ses->serverDomain) - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); @@ -2915,8 +2903,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr, remaining_words - 1); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1), GFP_KERNEL); @@ -2969,8 +2956,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(ses->serverDomain) kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } } else { /* ASCII */ @@ -2988,8 +2974,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len+1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; From 124a27fe32398a69d16bae374aeb17ad67a0ebbf Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 26 Jun 2006 13:47:59 +0000 Subject: [PATCH 035/556] [CIFS] Remove calls to to take f_owner.lock CIFS takes/releases f_owner.lock - why? It does not change anything in the fowner state. Remove this locking. Signed-off-by: Ingo Molnar Signed-off-by: Steve French --- fs/cifs/file.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 616b140534be..e9c1573f6aa7 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -110,7 +110,6 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, &pCifsInode->openFileList); } write_unlock(&GlobalSMBSeslock); - write_unlock(&file->f_owner.lock); if (pCifsInode->clientCanCacheRead) { /* we have the inode open somewhere else no need to discard cache data */ @@ -287,7 +286,6 @@ int cifs_open(struct inode *inode, struct file *file) goto out; } pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); - write_lock(&file->f_owner.lock); write_lock(&GlobalSMBSeslock); list_add(&pCifsFile->tlist, &pTcon->openFileList); @@ -298,7 +296,6 @@ int cifs_open(struct inode *inode, struct file *file) &oplock, buf, full_path, xid); } else { write_unlock(&GlobalSMBSeslock); - write_unlock(&file->f_owner.lock); } if (oplock & CIFS_CREATE_ACTION) { @@ -477,7 +474,6 @@ int cifs_close(struct inode *inode, struct file *file) pTcon = cifs_sb->tcon; if (pSMBFile) { pSMBFile->closePend = TRUE; - write_lock(&file->f_owner.lock); if (pTcon) { /* no sense reconnecting to close a file that is already closed */ @@ -492,23 +488,18 @@ int cifs_close(struct inode *inode, struct file *file) the struct would be in each open file, but this should give enough time to clear the socket */ - write_unlock(&file->f_owner.lock); cERROR(1,("close with pending writes")); msleep(timeout); - write_lock(&file->f_owner.lock); timeout *= 4; } - write_unlock(&file->f_owner.lock); rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid); - write_lock(&file->f_owner.lock); } } write_lock(&GlobalSMBSeslock); list_del(&pSMBFile->flist); list_del(&pSMBFile->tlist); write_unlock(&GlobalSMBSeslock); - write_unlock(&file->f_owner.lock); kfree(pSMBFile->search_resume_name); kfree(file->private_data); file->private_data = NULL; From d8deac5094988c7ad1127ee61f52c59a952fcabb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 036/556] [PATCH] devfs: Remove devfs from the kernel tree This is the first patch in a series of patches that removes devfs support from the kernel. This patch removes the core devfs code, and its private header file. Signed-off-by: Greg Kroah-Hartman --- fs/Makefile | 1 - fs/compat_ioctl.c | 1 - fs/devfs/Makefile | 8 - fs/devfs/base.c | 2836 ------------------------------- fs/devfs/util.c | 97 -- include/linux/compat_ioctl.h | 5 - include/linux/devfs_fs.h | 41 - include/linux/devfs_fs_kernel.h | 18 - 8 files changed, 3007 deletions(-) delete mode 100644 fs/devfs/Makefile delete mode 100644 fs/devfs/base.c delete mode 100644 fs/devfs/util.c delete mode 100644 include/linux/devfs_fs.h diff --git a/fs/Makefile b/fs/Makefile index d0ea6bfccf29..89135428a539 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -66,7 +66,6 @@ obj-$(CONFIG_MSDOS_FS) += msdos/ obj-$(CONFIG_VFAT_FS) += vfat/ obj-$(CONFIG_BFS_FS) += bfs/ obj-$(CONFIG_ISO9660_FS) += isofs/ -obj-$(CONFIG_DEVFS_FS) += devfs/ obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ obj-$(CONFIG_HFS_FS) += hfs/ obj-$(CONFIG_VXFS_FS) += freevxfs/ diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index d8ecfedef189..d8d50a70c58d 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/devfs/Makefile b/fs/devfs/Makefile deleted file mode 100644 index 6dd8d1245e2c..000000000000 --- a/fs/devfs/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the linux devfs-filesystem routines. -# - -obj-$(CONFIG_DEVFS_FS) += devfs.o - -devfs-objs := base.o util.o - diff --git a/fs/devfs/base.c b/fs/devfs/base.c deleted file mode 100644 index 51a97f132745..000000000000 --- a/fs/devfs/base.c +++ /dev/null @@ -1,2836 +0,0 @@ -/* devfs (Device FileSystem) driver. - - Copyright (C) 1998-2002 Richard Gooch - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Richard Gooch may be reached by email at rgooch@atnf.csiro.au - The postal address is: - Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. - - ChangeLog - - 19980110 Richard Gooch - Original version. - v0.1 - 19980111 Richard Gooch - Created per-fs inode table rather than using inode->u.generic_ip - v0.2 - 19980111 Richard Gooch - Created .epoch inode which has a ctime of 0. - Fixed loss of named pipes when dentries lost. - Fixed loss of inode data when devfs_register() follows mknod(). - v0.3 - 19980111 Richard Gooch - Fix for when compiling with CONFIG_KERNELD. - 19980112 Richard Gooch - Fix for readdir() which sometimes didn't show entries. - Added <> option to . - v0.4 - 19980113 Richard Gooch - Created function. - v0.5 - 19980115 Richard Gooch - Added subdirectory support. Major restructuring. - 19980116 Richard Gooch - Fixed to not search major=0,minor=0. - Added symlink support. - v0.6 - 19980120 Richard Gooch - Created function and support directory unregister - 19980120 Richard Gooch - Auto-ownership uses real uid/gid rather than effective uid/gid. - v0.7 - 19980121 Richard Gooch - Supported creation of sockets. - v0.8 - 19980122 Richard Gooch - Added DEVFS_FL_HIDE_UNREG flag. - Interface change to . - Created to support symlink(2). - v0.9 - 19980123 Richard Gooch - Added check to to check inode is in devfs. - Added optional traversal of symlinks. - v0.10 - 19980124 Richard Gooch - Created and . - v0.11 - 19980125 C. Scott Ananian - Created . - 19980125 Richard Gooch - Allow removal of symlinks. - v0.12 - 19980125 Richard Gooch - Created . - 19980126 Richard Gooch - Moved DEVFS_SUPER_MAGIC into header file. - Added DEVFS_FL_HIDE flag. - Created . - Created . - Fixed minor bug in . - 19980127 Richard Gooch - Changed interface to , , - , and . - Fixed inode times when symlink created with symlink(2). - v0.13 - 19980129 C. Scott Ananian - Exported , - and . - 19980129 Richard Gooch - Created to support unlink(2). - v0.14 - 19980129 Richard Gooch - Fixed kerneld support for entries in devfs subdirectories. - 19980130 Richard Gooch - Bugfixes in . - v0.15 - 19980207 Richard Gooch - Call kerneld when looking up unregistered entries. - v0.16 - 19980326 Richard Gooch - Modified interface to for symlink traversal. - v0.17 - 19980331 Richard Gooch - Fixed persistence bug with device numbers for manually created - device files. - Fixed problem with recreating symlinks with different content. - v0.18 - 19980401 Richard Gooch - Changed to CONFIG_KMOD. - Hide entries which are manually unlinked. - Always invalidate devfs dentry cache when registering entries. - Created to support rmdir(2). - Ensure directories created by are visible. - v0.19 - 19980402 Richard Gooch - Invalidate devfs dentry cache when making directories. - Invalidate devfs dentry cache when removing entries. - Fixed persistence bug with fifos. - v0.20 - 19980421 Richard Gooch - Print process command when debugging kerneld/kmod. - Added debugging for register/unregister/change operations. - 19980422 Richard Gooch - Added "devfs=" boot options. - v0.21 - 19980426 Richard Gooch - No longer lock/unlock superblock in . - Drop negative dentries when they are released. - Manage dcache more efficiently. - v0.22 - 19980427 Richard Gooch - Added DEVFS_FL_AUTO_DEVNUM flag. - v0.23 - 19980430 Richard Gooch - No longer set unnecessary methods. - v0.24 - 19980504 Richard Gooch - Added PID display to debugging message. - Added "after" debugging message to . - 19980519 Richard Gooch - Added "diread" and "diwrite" boot options. - 19980520 Richard Gooch - Fixed persistence problem with permissions. - v0.25 - 19980602 Richard Gooch - Support legacy device nodes. - Fixed bug where recreated inodes were hidden. - v0.26 - 19980602 Richard Gooch - Improved debugging in . - 19980607 Richard Gooch - No longer free old dentries in . - Free all dentries for a given entry when deleting inodes. - v0.27 - 19980627 Richard Gooch - Limit auto-device numbering to majors 128 to 239. - v0.28 - 19980629 Richard Gooch - Fixed inode times persistence problem. - v0.29 - 19980704 Richard Gooch - Fixed spelling in debug. - Fixed bug in parsing "dilookup". - v0.30 - 19980705 Richard Gooch - Fixed devfs inode leak when manually recreating inodes. - Fixed permission persistence problem when recreating inodes. - v0.31 - 19980727 Richard Gooch - Removed harmless "unused variable" compiler warning. - Fixed modes for manually recreated device nodes. - v0.32 - 19980728 Richard Gooch - Added NULL devfs inode warning in . - Force all inode nlink values to 1. - v0.33 - 19980730 Richard Gooch - Added "dimknod" boot option. - Set inode nlink to 0 when freeing dentries. - Fixed modes for manually recreated symlinks. - v0.34 - 19980802 Richard Gooch - Fixed bugs in recreated directories and symlinks. - v0.35 - 19980806 Richard Gooch - Fixed bugs in recreated device nodes. - 19980807 Richard Gooch - Fixed bug in currently unused . - Defined new type. - Improved debugging when getting entries. - Fixed bug where directories could be emptied. - v0.36 - 19980809 Richard Gooch - Replaced dummy .epoch inode with .devfsd character device. - 19980810 Richard Gooch - Implemented devfsd protocol revision 0. - v0.37 - 19980819 Richard Gooch - Added soothing message to warning in . - v0.38 - 19980829 Richard Gooch - Use GCC extensions for structure initialisations. - Implemented async open notification. - Incremented devfsd protocol revision to 1. - v0.39 - 19980908 Richard Gooch - Moved async open notification to end of . - v0.40 - 19980910 Richard Gooch - Prepended "/dev/" to module load request. - Renamed to . - v0.41 - 19980910 Richard Gooch - Fixed typo "AYSNC" -> "ASYNC". - v0.42 - 19980910 Richard Gooch - Added open flag for files. - v0.43 - 19980927 Richard Gooch - Set i_blocks=0 and i_blksize=1024 in . - v0.44 - 19981005 Richard Gooch - Added test for empty <> in . - Renamed to and published. - v0.45 - 19981006 Richard Gooch - Created . - v0.46 - 19981007 Richard Gooch - Limit auto-device numbering to majors 144 to 239. - v0.47 - 19981010 Richard Gooch - Updated for VFS change in 2.1.125. - v0.48 - 19981022 Richard Gooch - Created DEVFS_ FL_COMPAT flag. - v0.49 - 19981023 Richard Gooch - Created "nocompat" boot option. - v0.50 - 19981025 Richard Gooch - Replaced "mount" boot option with "nomount". - v0.51 - 19981110 Richard Gooch - Created "only" boot option. - v0.52 - 19981112 Richard Gooch - Added DEVFS_FL_REMOVABLE flag. - v0.53 - 19981114 Richard Gooch - Only call on first call to - . - v0.54 - 19981205 Richard Gooch - Updated for VFS change in 2.1.131. - v0.55 - 19981218 Richard Gooch - Created . - 19981220 Richard Gooch - Check for partitions on removable media in . - v0.56 - 19990118 Richard Gooch - Added support for registering regular files. - Created . - Update devfs inodes from entries if not changed through FS. - v0.57 - 19990124 Richard Gooch - Fixed to only initialise temporary inodes. - Trap for NULL fops in . - Return -ENODEV in for non-driver inodes. - v0.58 - 19990126 Richard Gooch - Switched from PATH_MAX to DEVFS_PATHLEN. - v0.59 - 19990127 Richard Gooch - Created "nottycompat" boot option. - v0.60 - 19990318 Richard Gooch - Fixed to not overrun event buffer. - v0.61 - 19990329 Richard Gooch - Created . - v0.62 - 19990330 Richard Gooch - Don't return unregistred entries in . - Panic in if entry unregistered. - 19990401 Richard Gooch - Don't panic in for duplicates. - v0.63 - 19990402 Richard Gooch - Don't unregister already unregistered entries in . - v0.64 - 19990510 Richard Gooch - Disable warning messages when unable to read partition table for - removable media. - v0.65 - 19990512 Richard Gooch - Updated for VFS change in 2.3.1-pre1. - Created "oops-on-panic" boot option. - Improved debugging in and . - v0.66 - 19990519 Richard Gooch - Added documentation for some functions. - 19990525 Richard Gooch - Removed "oops-on-panic" boot option: now always Oops. - v0.67 - 19990531 Richard Gooch - Improved debugging in . - v0.68 - 19990604 Richard Gooch - Added "diunlink" and "nokmod" boot options. - Removed superfluous warning message in . - v0.69 - 19990611 Richard Gooch - Took account of change to . - v0.70 - 19990614 Richard Gooch - Created separate event queue for each mounted devfs. - Removed . - Created new ioctl()s. - Incremented devfsd protocol revision to 3. - Fixed bug when re-creating directories: contents were lost. - Block access to inodes until devfsd updates permissions. - 19990615 Richard Gooch - Support 2.2.x kernels. - v0.71 - 19990623 Richard Gooch - Switched to sending process uid/gid to devfsd. - Renamed to . - Added DEVFSD_NOTIFY_LOOKUP event. - 19990624 Richard Gooch - Added DEVFSD_NOTIFY_CHANGE event. - Incremented devfsd protocol revision to 4. - v0.72 - 19990713 Richard Gooch - Return EISDIR rather than EINVAL for read(2) on directories. - v0.73 - 19990809 Richard Gooch - Changed to new __init scheme. - v0.74 - 19990901 Richard Gooch - Changed remaining function declarations to new __init scheme. - v0.75 - 19991013 Richard Gooch - Created , , - and . - Added <> parameter to , , - and . - Work sponsored by SGI. - v0.76 - 19991017 Richard Gooch - Allow multiple unregistrations. - Work sponsored by SGI. - v0.77 - 19991026 Richard Gooch - Added major and minor number to devfsd protocol. - Incremented devfsd protocol revision to 5. - Work sponsored by SGI. - v0.78 - 19991030 Richard Gooch - Support info pointer for all devfs entry types. - Added <> parameter to and - . - Work sponsored by SGI. - v0.79 - 19991031 Richard Gooch - Support "../" when searching devfs namespace. - Work sponsored by SGI. - v0.80 - 19991101 Richard Gooch - Created . - Work sponsored by SGI. - v0.81 - 19991103 Richard Gooch - Exported . - Work sponsored by SGI. - v0.82 - 19991104 Richard Gooch - Removed unused . - 19991105 Richard Gooch - Do not hide entries from devfsd or children. - Removed DEVFS_ FL_TTY_COMPAT flag. - Removed "nottycompat" boot option. - Removed . - Work sponsored by SGI. - v0.83 - 19991107 Richard Gooch - Added DEVFS_FL_WAIT flag. - Work sponsored by SGI. - v0.84 - 19991107 Richard Gooch - Support new "disc" naming scheme in . - Allow NULL fops in . - Work sponsored by SGI. - v0.85 - 19991110 Richard Gooch - Fall back to major table if NULL fops given to . - Work sponsored by SGI. - v0.86 - 19991204 Richard Gooch - Support fifos when unregistering. - Work sponsored by SGI. - v0.87 - 19991209 Richard Gooch - Removed obsolete DEVFS_ FL_COMPAT and DEVFS_ FL_TOLERANT flags. - Work sponsored by SGI. - v0.88 - 19991214 Richard Gooch - Removed kmod support. - Work sponsored by SGI. - v0.89 - 19991216 Richard Gooch - Improved debugging in . - Ensure dentries created by devfsd will be cleaned up. - Work sponsored by SGI. - v0.90 - 19991223 Richard Gooch - Created . - Work sponsored by SGI. - v0.91 - 20000203 Richard Gooch - Ported to kernel 2.3.42. - Removed . - Work sponsored by SGI. - v0.92 - 20000306 Richard Gooch - Added DEVFS_ FL_NO_PERSISTENCE flag. - Removed unnecessary call to in - . - Work sponsored by SGI. - v0.93 - 20000413 Richard Gooch - Set inode->i_size to correct size for symlinks. - 20000414 Richard Gooch - Only give lookup() method to directories to comply with new VFS - assumptions. - Work sponsored by SGI. - 20000415 Richard Gooch - Remove unnecessary tests in symlink methods. - Don't kill existing block ops in . - Work sponsored by SGI. - v0.94 - 20000424 Richard Gooch - Don't create missing directories in . - Work sponsored by SGI. - v0.95 - 20000430 Richard Gooch - Added CONFIG_DEVFS_MOUNT. - Work sponsored by SGI. - v0.96 - 20000608 Richard Gooch - Disabled multi-mount capability (use VFS bindings instead). - Work sponsored by SGI. - v0.97 - 20000610 Richard Gooch - Switched to FS_SINGLE to disable multi-mounts. - 20000612 Richard Gooch - Removed module support. - Removed multi-mount code. - Removed compatibility macros: VFS has changed too much. - Work sponsored by SGI. - v0.98 - 20000614 Richard Gooch - Merged devfs inode into devfs entry. - Work sponsored by SGI. - v0.99 - 20000619 Richard Gooch - Removed dead code in which used to call - . - Work sponsored by SGI. - v0.100 - 20000621 Richard Gooch - Changed interface to . - Work sponsored by SGI. - v0.101 - 20000622 Richard Gooch - Simplified interface to and . - Simplified interface to . - Work sponsored by SGI. - v0.102 - 20010519 Richard Gooch - Ensure terminates string for root entry. - Exported to modules. - 20010520 Richard Gooch - Make send events to devfsd. - Cleaned up option processing in . - 20010521 Richard Gooch - Fixed bugs in handling symlinks: could leak or cause Oops. - 20010522 Richard Gooch - Cleaned up directory handling by separating fops. - v0.103 - 20010601 Richard Gooch - Fixed handling of inverted options in . - v0.104 - 20010604 Richard Gooch - Adjusted to account for fix. - v0.105 - 20010617 Richard Gooch - Answered question posed by Al Viro and removed his comments. - Moved setting of registered flag after other fields are changed. - Fixed race between and . - Global VFS changes added bogus BKL to : removed. - Widened locking in and . - Replaced stack usage with kmalloc. - Simplified locking in and fixed memory leak. - v0.106 - 20010709 Richard Gooch - Removed broken devnum allocation and use . - Fixed old devnum leak by calling new . - v0.107 - 20010712 Richard Gooch - Fixed bug in which could hang boot process. - v0.108 - 20010730 Richard Gooch - Added DEVFSD_NOTIFY_DELETE event. - 20010801 Richard Gooch - Removed #include . - v0.109 - 20010807 Richard Gooch - Fixed inode table races by removing it and using - inode->u.generic_ip instead. - Moved into . - Moved into . - v0.110 - 20010808 Richard Gooch - Fixed race in for uni-processor. - v0.111 - 20010818 Richard Gooch - Removed remnant of multi-mount support in . - Removed unused DEVFS_FL_SHOW_UNREG flag. - v0.112 - 20010820 Richard Gooch - Removed nlink field from struct devfs_inode. - v0.113 - 20010823 Richard Gooch - Replaced BKL with global rwsem to protect symlink data (quick - and dirty hack). - v0.114 - 20010827 Richard Gooch - Replaced global rwsem for symlink with per-link refcount. - v0.115 - 20010919 Richard Gooch - Set inode->i_mapping->a_ops for block nodes in . - v0.116 - 20011008 Richard Gooch - Fixed overrun in by removing function (not needed). - 20011009 Richard Gooch - Fixed buffer underrun in . - 20011029 Richard Gooch - Fixed race in when setting event mask. - 20011114 Richard Gooch - First release of new locking code. - v1.0 - 20011117 Richard Gooch - Discard temporary buffer, now use "%s" for dentry names. - 20011118 Richard Gooch - Don't generate path in : use fake entry instead. - Use "existing" directory in <_devfs_make_parent_for_leaf>. - 20011122 Richard Gooch - Use slab cache rather than fixed buffer for devfsd events. - v1.1 - 20011125 Richard Gooch - Send DEVFSD_NOTIFY_REGISTERED events in . - 20011127 Richard Gooch - Fixed locking bug in due to typo. - Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from - devfsd or children. - v1.2 - 20011202 Richard Gooch - Fixed bug in : was dereferencing freed pointer. - v1.3 - 20011203 Richard Gooch - Fixed bug in : was dereferencing freed pointer. - Added process group check for devfsd privileges. - v1.4 - 20011204 Richard Gooch - Use SLAB_ATOMIC in from . - v1.5 - 20011211 Richard Gooch - Return old entry in for 2.4.x kernels. - 20011212 Richard Gooch - Increment refcount on module in . - 20011215 Richard Gooch - Created and exported . - Increment refcount on module in . - Created . - v1.6 - 20011216 Richard Gooch - Added poisoning to . - Improved debugging messages. - v1.7 - 20011221 Richard Gooch - Corrected (made useful) debugging message in . - Moved in to - 20011224 Richard Gooch - Added magic number to guard against scribbling drivers. - 20011226 Richard Gooch - Only return old entry in if a directory. - Defined macros for error and debug messages. - v1.8 - 20020113 Richard Gooch - Fixed (rare, old) race in . - v1.9 - 20020120 Richard Gooch - Fixed deadlock bug in . - Tag VFS deletable in if handle ignored. - v1.10 - 20020129 Richard Gooch - Added KERN_* to remaining messages. - Cleaned up declaration of . - v1.11 - 20020219 Richard Gooch - Changed to allow later additions if not yet empty. - v1.12 - 20020406 Richard Gooch - Removed silently introduced calls to lock_kernel() and - unlock_kernel() due to recent VFS locking changes. BKL isn't - required in devfs. - v1.13 - 20020428 Richard Gooch - Removed 2.4.x compatibility code. - v1.14 - 20020510 Richard Gooch - Added BKL to because drivers still need it. - v1.15 - 20020512 Richard Gooch - Protected and - from changing directory contents. - v1.16 - 20020514 Richard Gooch - Minor cleanup of . - v1.17 - 20020721 Richard Gooch - Switched to ISO C structure field initialisers. - Switch to set_current_state() and move before add_wait_queue(). - 20020722 Richard Gooch - Fixed devfs entry leak in when *readdir fails. - v1.18 - 20020725 Richard Gooch - Created . - v1.19 - 20020728 Richard Gooch - Removed deprecated . - v1.20 - 20020820 Richard Gooch - Fixed module unload race in . - v1.21 - 20021013 Richard Gooch - Removed DEVFS_ FL_AUTO_OWNER. - Switched lingering structure field initialiser to ISO C. - Added locking when updating FCB flags. - v1.22 -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define DEVFS_VERSION "2004-01-31" - -#define DEVFS_NAME "devfs" - -#define FIRST_INODE 1 - -#define STRING_LENGTH 256 -#define FAKE_BLOCK_SIZE 1024 -#define POISON_PTR ( *(void **) poison_array ) -#define MAGIC_VALUE 0x327db823 - -#ifndef TRUE -# define TRUE 1 -# define FALSE 0 -#endif - -#define MODE_DIR (S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO) - -#define DEBUG_NONE 0x0000000 -#define DEBUG_MODULE_LOAD 0x0000001 -#define DEBUG_REGISTER 0x0000002 -#define DEBUG_UNREGISTER 0x0000004 -#define DEBUG_FREE 0x0000008 -#define DEBUG_SET_FLAGS 0x0000010 -#define DEBUG_S_READ 0x0000100 /* Break */ -#define DEBUG_I_LOOKUP 0x0001000 /* Break */ -#define DEBUG_I_CREATE 0x0002000 -#define DEBUG_I_GET 0x0004000 -#define DEBUG_I_CHANGE 0x0008000 -#define DEBUG_I_UNLINK 0x0010000 -#define DEBUG_I_RLINK 0x0020000 -#define DEBUG_I_FLINK 0x0040000 -#define DEBUG_I_MKNOD 0x0080000 -#define DEBUG_F_READDIR 0x0100000 /* Break */ -#define DEBUG_D_DELETE 0x1000000 /* Break */ -#define DEBUG_D_RELEASE 0x2000000 -#define DEBUG_D_IPUT 0x4000000 -#define DEBUG_ALL 0xfffffff -#define DEBUG_DISABLED DEBUG_NONE - -#define OPTION_NONE 0x00 -#define OPTION_MOUNT 0x01 - -#define PRINTK(format, args...) \ - {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);} - -#define OOPS(format, args...) \ - {printk (KERN_CRIT "%s" format, __FUNCTION__ , ## args); \ - printk ("Forcing Oops\n"); \ - BUG();} - -#ifdef CONFIG_DEVFS_DEBUG -# define VERIFY_ENTRY(de) \ - {if ((de) && (de)->magic_number != MAGIC_VALUE) \ - OOPS ("(%p): bad magic value: %x\n", (de), (de)->magic_number);} -# define WRITE_ENTRY_MAGIC(de,magic) (de)->magic_number = (magic) -# define DPRINTK(flag, format, args...) \ - {if (devfs_debug & flag) \ - printk (KERN_INFO "%s" format, __FUNCTION__ , ## args);} -#else -# define VERIFY_ENTRY(de) -# define WRITE_ENTRY_MAGIC(de,magic) -# define DPRINTK(flag, format, args...) -#endif - -typedef struct devfs_entry *devfs_handle_t; - -struct directory_type { - rwlock_t lock; /* Lock for searching(R)/updating(W) */ - struct devfs_entry *first; - struct devfs_entry *last; - unsigned char no_more_additions:1; -}; - -struct symlink_type { - unsigned int length; /* Not including the NULL-termimator */ - char *linkname; /* This is NULL-terminated */ -}; - -struct devfs_inode { /* This structure is for "persistent" inode storage */ - struct dentry *dentry; - struct timespec atime; - struct timespec mtime; - struct timespec ctime; - unsigned int ino; /* Inode number as seen in the VFS */ - uid_t uid; - gid_t gid; -}; - -struct devfs_entry { -#ifdef CONFIG_DEVFS_DEBUG - unsigned int magic_number; -#endif - void *info; - atomic_t refcount; /* When this drops to zero, it's unused */ - union { - struct directory_type dir; - dev_t dev; - struct symlink_type symlink; - const char *name; /* Only used for (mode == 0) */ - } u; - struct devfs_entry *prev; /* Previous entry in the parent directory */ - struct devfs_entry *next; /* Next entry in the parent directory */ - struct devfs_entry *parent; /* The parent directory */ - struct devfs_inode inode; - umode_t mode; - unsigned short namelen; /* I think 64k+ filenames are a way off... */ - unsigned char vfs:1; /* Whether the VFS may delete the entry */ - char name[1]; /* This is just a dummy: the allocated array - is bigger. This is NULL-terminated */ -}; - -/* The root of the device tree */ -static struct devfs_entry *root_entry; - -struct devfsd_buf_entry { - struct devfs_entry *de; /* The name is generated with this */ - unsigned short type; /* The type of event */ - umode_t mode; - uid_t uid; - gid_t gid; - struct devfsd_buf_entry *next; -}; - -struct fs_info { /* This structure is for the mounted devfs */ - struct super_block *sb; - spinlock_t devfsd_buffer_lock; /* Lock when inserting/deleting events */ - struct devfsd_buf_entry *devfsd_first_event; - struct devfsd_buf_entry *devfsd_last_event; - volatile int devfsd_sleeping; - volatile struct task_struct *devfsd_task; - volatile pid_t devfsd_pgrp; - volatile struct file *devfsd_file; - struct devfsd_notify_struct *devfsd_info; - volatile unsigned long devfsd_event_mask; - atomic_t devfsd_overrun_count; - wait_queue_head_t devfsd_wait_queue; /* Wake devfsd on input */ - wait_queue_head_t revalidate_wait_queue; /* Wake when devfsd sleeps */ -}; - -static struct fs_info fs_info = {.devfsd_buffer_lock = SPIN_LOCK_UNLOCKED }; -static kmem_cache_t *devfsd_buf_cache; -#ifdef CONFIG_DEVFS_DEBUG -static unsigned int devfs_debug_init __initdata = DEBUG_NONE; -static unsigned int devfs_debug = DEBUG_NONE; -static DEFINE_SPINLOCK(stat_lock); -static unsigned int stat_num_entries; -static unsigned int stat_num_bytes; -#endif -static unsigned char poison_array[8] = - { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a }; - -#ifdef CONFIG_DEVFS_MOUNT -static unsigned int boot_options = OPTION_MOUNT; -#else -static unsigned int boot_options = OPTION_NONE; -#endif - -/* Forward function declarations */ -static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir, - const char *name, int namelen, - int traverse_symlink); -static ssize_t devfsd_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos); -static int devfsd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static int devfsd_close(struct inode *inode, struct file *file); -#ifdef CONFIG_DEVFS_DEBUG -static ssize_t stat_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos); -static const struct file_operations stat_fops = { - .open = nonseekable_open, - .read = stat_read, -}; -#endif - -/* Devfs daemon file operations */ -static const struct file_operations devfsd_fops = { - .open = nonseekable_open, - .read = devfsd_read, - .ioctl = devfsd_ioctl, - .release = devfsd_close, -}; - -/* Support functions follow */ - -/** - * devfs_get - Get a reference to a devfs entry. - * @de: The devfs entry. - */ - -static struct devfs_entry *devfs_get(struct devfs_entry *de) -{ - VERIFY_ENTRY(de); - if (de) - atomic_inc(&de->refcount); - return de; -} /* End Function devfs_get */ - -/** - * devfs_put - Put (release) a reference to a devfs entry. - * @de: The handle to the devfs entry. - */ - -static void devfs_put(devfs_handle_t de) -{ - if (!de) - return; - VERIFY_ENTRY(de); - if (de->info == POISON_PTR) - OOPS("(%p): poisoned pointer\n", de); - if (!atomic_dec_and_test(&de->refcount)) - return; - if (de == root_entry) - OOPS("(%p): root entry being freed\n", de); - DPRINTK(DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n", - de->name, de, de->parent, - de->parent ? de->parent->name : "no parent"); - if (S_ISLNK(de->mode)) - kfree(de->u.symlink.linkname); - WRITE_ENTRY_MAGIC(de, 0); -#ifdef CONFIG_DEVFS_DEBUG - spin_lock(&stat_lock); - --stat_num_entries; - stat_num_bytes -= sizeof *de + de->namelen; - if (S_ISLNK(de->mode)) - stat_num_bytes -= de->u.symlink.length + 1; - spin_unlock(&stat_lock); -#endif - de->info = POISON_PTR; - kfree(de); -} /* End Function devfs_put */ - -/** - * _devfs_search_dir - Search for a devfs entry in a directory. - * @dir: The directory to search. - * @name: The name of the entry to search for. - * @namelen: The number of characters in @name. - * - * Search for a devfs entry in a directory and returns a pointer to the entry - * on success, else %NULL. The directory must be locked already. - * An implicit devfs_get() is performed on the returned entry. - */ - -static struct devfs_entry *_devfs_search_dir(struct devfs_entry *dir, - const char *name, - unsigned int namelen) -{ - struct devfs_entry *curr; - - if (!S_ISDIR(dir->mode)) { - PRINTK("(%s): not a directory\n", dir->name); - return NULL; - } - for (curr = dir->u.dir.first; curr != NULL; curr = curr->next) { - if (curr->namelen != namelen) - continue; - if (memcmp(curr->name, name, namelen) == 0) - break; - /* Not found: try the next one */ - } - return devfs_get(curr); -} /* End Function _devfs_search_dir */ - -/** - * _devfs_alloc_entry - Allocate a devfs entry. - * @name: the name of the entry - * @namelen: the number of characters in @name - * @mode: the mode for the entry - * - * Allocate a devfs entry and returns a pointer to the entry on success, else - * %NULL. - */ - -static struct devfs_entry *_devfs_alloc_entry(const char *name, - unsigned int namelen, - umode_t mode) -{ - struct devfs_entry *new; - static unsigned long inode_counter = FIRST_INODE; - static DEFINE_SPINLOCK(counter_lock); - - if (name && (namelen < 1)) - namelen = strlen(name); - if ((new = kmalloc(sizeof *new + namelen, GFP_KERNEL)) == NULL) - return NULL; - memset(new, 0, sizeof *new + namelen); /* Will set '\0' on name */ - new->mode = mode; - if (S_ISDIR(mode)) - rwlock_init(&new->u.dir.lock); - atomic_set(&new->refcount, 1); - spin_lock(&counter_lock); - new->inode.ino = inode_counter++; - spin_unlock(&counter_lock); - if (name) - memcpy(new->name, name, namelen); - new->namelen = namelen; - WRITE_ENTRY_MAGIC(new, MAGIC_VALUE); -#ifdef CONFIG_DEVFS_DEBUG - spin_lock(&stat_lock); - ++stat_num_entries; - stat_num_bytes += sizeof *new + namelen; - spin_unlock(&stat_lock); -#endif - return new; -} /* End Function _devfs_alloc_entry */ - -/** - * _devfs_append_entry - Append a devfs entry to a directory's child list. - * @dir: The directory to add to. - * @de: The devfs entry to append. - * @old_de: If an existing entry exists, it will be written here. This may - * be %NULL. An implicit devfs_get() is performed on this entry. - * - * Append a devfs entry to a directory's list of children, checking first to - * see if an entry of the same name exists. The directory will be locked. - * The value 0 is returned on success, else a negative error code. - * On failure, an implicit devfs_put() is performed on %de. - */ - -static int _devfs_append_entry(devfs_handle_t dir, devfs_handle_t de, - devfs_handle_t * old_de) -{ - int retval; - - if (old_de) - *old_de = NULL; - if (!S_ISDIR(dir->mode)) { - PRINTK("(%s): dir: \"%s\" is not a directory\n", de->name, - dir->name); - devfs_put(de); - return -ENOTDIR; - } - write_lock(&dir->u.dir.lock); - if (dir->u.dir.no_more_additions) - retval = -ENOENT; - else { - struct devfs_entry *old; - - old = _devfs_search_dir(dir, de->name, de->namelen); - if (old_de) - *old_de = old; - else - devfs_put(old); - if (old == NULL) { - de->parent = dir; - de->prev = dir->u.dir.last; - /* Append to the directory's list of children */ - if (dir->u.dir.first == NULL) - dir->u.dir.first = de; - else - dir->u.dir.last->next = de; - dir->u.dir.last = de; - retval = 0; - } else - retval = -EEXIST; - } - write_unlock(&dir->u.dir.lock); - if (retval) - devfs_put(de); - return retval; -} /* End Function _devfs_append_entry */ - -/** - * _devfs_get_root_entry - Get the root devfs entry. - * - * Returns the root devfs entry on success, else %NULL. - * - * TODO it must be called asynchronously due to the fact - * that devfs is initialized relatively late. Proper way - * is to remove module_init from init_devfs_fs and manually - * call it early enough during system init - */ - -static struct devfs_entry *_devfs_get_root_entry(void) -{ - struct devfs_entry *new; - static DEFINE_SPINLOCK(root_lock); - - if (root_entry) - return root_entry; - - new = _devfs_alloc_entry(NULL, 0, MODE_DIR); - if (new == NULL) - return NULL; - - spin_lock(&root_lock); - if (root_entry) { - spin_unlock(&root_lock); - devfs_put(new); - return root_entry; - } - root_entry = new; - spin_unlock(&root_lock); - - return root_entry; -} /* End Function _devfs_get_root_entry */ - -/** - * _devfs_descend - Descend down a tree using the next component name. - * @dir: The directory to search. - * @name: The component name to search for. - * @namelen: The length of %name. - * @next_pos: The position of the next '/' or '\0' is written here. - * - * Descend into a directory, searching for a component. This function forms - * the core of a tree-walking algorithm. The directory will be locked. - * The devfs entry corresponding to the component is returned. If there is - * no matching entry, %NULL is returned. - * An implicit devfs_get() is performed on the returned entry. - */ - -static struct devfs_entry *_devfs_descend(struct devfs_entry *dir, - const char *name, int namelen, - int *next_pos) -{ - const char *stop, *ptr; - struct devfs_entry *entry; - - if ((namelen >= 3) && (strncmp(name, "../", 3) == 0)) { /* Special-case going to parent directory */ - *next_pos = 3; - return devfs_get(dir->parent); - } - stop = name + namelen; - /* Search for a possible '/' */ - for (ptr = name; (ptr < stop) && (*ptr != '/'); ++ptr) ; - *next_pos = ptr - name; - read_lock(&dir->u.dir.lock); - entry = _devfs_search_dir(dir, name, *next_pos); - read_unlock(&dir->u.dir.lock); - return entry; -} /* End Function _devfs_descend */ - -static devfs_handle_t _devfs_make_parent_for_leaf(struct devfs_entry *dir, - const char *name, - int namelen, int *leaf_pos) -{ - int next_pos = 0; - - if (dir == NULL) - dir = _devfs_get_root_entry(); - if (dir == NULL) - return NULL; - devfs_get(dir); - /* Search for possible trailing component and ignore it */ - for (--namelen; (namelen > 0) && (name[namelen] != '/'); --namelen) ; - *leaf_pos = (name[namelen] == '/') ? (namelen + 1) : 0; - for (; namelen > 0; name += next_pos, namelen -= next_pos) { - struct devfs_entry *de, *old = NULL; - - if ((de = - _devfs_descend(dir, name, namelen, &next_pos)) == NULL) { - de = _devfs_alloc_entry(name, next_pos, MODE_DIR); - devfs_get(de); - if (!de || _devfs_append_entry(dir, de, &old)) { - devfs_put(de); - if (!old || !S_ISDIR(old->mode)) { - devfs_put(old); - devfs_put(dir); - return NULL; - } - de = old; /* Use the existing directory */ - } - } - if (de == dir->parent) { - devfs_put(dir); - devfs_put(de); - return NULL; - } - devfs_put(dir); - dir = de; - if (name[next_pos] == '/') - ++next_pos; - } - return dir; -} /* End Function _devfs_make_parent_for_leaf */ - -static devfs_handle_t _devfs_prepare_leaf(devfs_handle_t * dir, - const char *name, umode_t mode) -{ - int namelen, leaf_pos; - struct devfs_entry *de; - - namelen = strlen(name); - if ((*dir = _devfs_make_parent_for_leaf(*dir, name, namelen, - &leaf_pos)) == NULL) { - PRINTK("(%s): could not create parent path\n", name); - return NULL; - } - if ((de = _devfs_alloc_entry(name + leaf_pos, namelen - leaf_pos, mode)) - == NULL) { - PRINTK("(%s): could not allocate entry\n", name); - devfs_put(*dir); - return NULL; - } - return de; -} /* End Function _devfs_prepare_leaf */ - -static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir, - const char *name, int namelen, - int traverse_symlink) -{ - int next_pos = 0; - - if (dir == NULL) - dir = _devfs_get_root_entry(); - if (dir == NULL) - return NULL; - devfs_get(dir); - for (; namelen > 0; name += next_pos, namelen -= next_pos) { - struct devfs_entry *de, *link; - - if (!S_ISDIR(dir->mode)) { - devfs_put(dir); - return NULL; - } - - if ((de = - _devfs_descend(dir, name, namelen, &next_pos)) == NULL) { - devfs_put(dir); - return NULL; - } - if (S_ISLNK(de->mode) && traverse_symlink) { /* Need to follow the link: this is a stack chomper */ - /* FIXME what if it puts outside of mounted tree? */ - link = _devfs_walk_path(dir, de->u.symlink.linkname, - de->u.symlink.length, TRUE); - devfs_put(de); - if (!link) { - devfs_put(dir); - return NULL; - } - de = link; - } - devfs_put(dir); - dir = de; - if (name[next_pos] == '/') - ++next_pos; - } - return dir; -} /* End Function _devfs_walk_path */ - -/** - * _devfs_find_entry - Find a devfs entry. - * @dir: The handle to the parent devfs directory entry. If this is %NULL the - * name is relative to the root of the devfs. - * @name: The name of the entry. This may be %NULL. - * @traverse_symlink: If %TRUE then symbolic links are traversed. - * - * Returns the devfs_entry pointer on success, else %NULL. An implicit - * devfs_get() is performed. - */ - -static struct devfs_entry *_devfs_find_entry(devfs_handle_t dir, - const char *name, - int traverse_symlink) -{ - unsigned int namelen = strlen(name); - - if (name[0] == '/') { - /* Skip leading pathname component */ - if (namelen < 2) { - PRINTK("(%s): too short\n", name); - return NULL; - } - for (++name, --namelen; (*name != '/') && (namelen > 0); - ++name, --namelen) ; - if (namelen < 2) { - PRINTK("(%s): too short\n", name); - return NULL; - } - ++name; - --namelen; - } - return _devfs_walk_path(dir, name, namelen, traverse_symlink); -} /* End Function _devfs_find_entry */ - -static struct devfs_entry *get_devfs_entry_from_vfs_inode(struct inode *inode) -{ - if (inode == NULL) - return NULL; - VERIFY_ENTRY((struct devfs_entry *)inode->u.generic_ip); - return inode->u.generic_ip; -} /* End Function get_devfs_entry_from_vfs_inode */ - -/** - * free_dentry - Free the dentry for a device entry and invalidate inode. - * @de: The entry. - * - * This must only be called after the entry has been unhooked from its - * parent directory. - */ - -static void free_dentry(struct devfs_entry *de) -{ - struct dentry *dentry = de->inode.dentry; - - if (!dentry) - return; - spin_lock(&dcache_lock); - dget_locked(dentry); - spin_unlock(&dcache_lock); - /* Forcefully remove the inode */ - if (dentry->d_inode != NULL) - dentry->d_inode->i_nlink = 0; - d_drop(dentry); - dput(dentry); -} /* End Function free_dentry */ - -/** - * is_devfsd_or_child - Test if the current process is devfsd or one of its children. - * @fs_info: The filesystem information. - * - * Returns %TRUE if devfsd or child, else %FALSE. - */ - -static int is_devfsd_or_child(struct fs_info *fs_info) -{ - struct task_struct *p = current; - - if (p == fs_info->devfsd_task) - return (TRUE); - if (process_group(p) == fs_info->devfsd_pgrp) - return (TRUE); - read_lock(&tasklist_lock); - for (; p != &init_task; p = p->real_parent) { - if (p == fs_info->devfsd_task) { - read_unlock(&tasklist_lock); - return (TRUE); - } - } - read_unlock(&tasklist_lock); - return (FALSE); -} /* End Function is_devfsd_or_child */ - -/** - * devfsd_queue_empty - Test if devfsd has work pending in its event queue. - * @fs_info: The filesystem information. - * - * Returns %TRUE if the queue is empty, else %FALSE. - */ - -static inline int devfsd_queue_empty(struct fs_info *fs_info) -{ - return (fs_info->devfsd_last_event) ? FALSE : TRUE; -} /* End Function devfsd_queue_empty */ - -/** - * wait_for_devfsd_finished - Wait for devfsd to finish processing its event queue. - * @fs_info: The filesystem information. - * - * Returns %TRUE if no more waiting will be required, else %FALSE. - */ - -static int wait_for_devfsd_finished(struct fs_info *fs_info) -{ - DECLARE_WAITQUEUE(wait, current); - - if (fs_info->devfsd_task == NULL) - return (TRUE); - if (devfsd_queue_empty(fs_info) && fs_info->devfsd_sleeping) - return TRUE; - if (is_devfsd_or_child(fs_info)) - return (FALSE); - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&fs_info->revalidate_wait_queue, &wait); - if (!devfsd_queue_empty(fs_info) || !fs_info->devfsd_sleeping) - if (fs_info->devfsd_task) - schedule(); - remove_wait_queue(&fs_info->revalidate_wait_queue, &wait); - __set_current_state(TASK_RUNNING); - return (TRUE); -} /* End Function wait_for_devfsd_finished */ - -/** - * devfsd_notify_de - Notify the devfsd daemon of a change. - * @de: The devfs entry that has changed. This and all parent entries will - * have their reference counts incremented if the event was queued. - * @type: The type of change. - * @mode: The mode of the entry. - * @uid: The user ID. - * @gid: The group ID. - * @fs_info: The filesystem info. - * - * Returns %TRUE if an event was queued and devfsd woken up, else %FALSE. - */ - -static int devfsd_notify_de(struct devfs_entry *de, - unsigned short type, umode_t mode, - uid_t uid, gid_t gid, struct fs_info *fs_info) -{ - struct devfsd_buf_entry *entry; - struct devfs_entry *curr; - - if (!(fs_info->devfsd_event_mask & (1 << type))) - return (FALSE); - if ((entry = kmem_cache_alloc(devfsd_buf_cache, SLAB_KERNEL)) == NULL) { - atomic_inc(&fs_info->devfsd_overrun_count); - return (FALSE); - } - for (curr = de; curr != NULL; curr = curr->parent) - devfs_get(curr); - entry->de = de; - entry->type = type; - entry->mode = mode; - entry->uid = uid; - entry->gid = gid; - entry->next = NULL; - spin_lock(&fs_info->devfsd_buffer_lock); - if (!fs_info->devfsd_first_event) - fs_info->devfsd_first_event = entry; - if (fs_info->devfsd_last_event) - fs_info->devfsd_last_event->next = entry; - fs_info->devfsd_last_event = entry; - spin_unlock(&fs_info->devfsd_buffer_lock); - wake_up_interruptible(&fs_info->devfsd_wait_queue); - return (TRUE); -} /* End Function devfsd_notify_de */ - -/** - * devfsd_notify - Notify the devfsd daemon of a change. - * @de: The devfs entry that has changed. - * @type: The type of change event. - * @wait: If TRUE, the function waits for the daemon to finish processing - * the event. - */ - -static void devfsd_notify(struct devfs_entry *de, unsigned short type) -{ - devfsd_notify_de(de, type, de->mode, current->euid, - current->egid, &fs_info); -} - -static int devfs_mk_dev(dev_t dev, umode_t mode, const char *fmt, va_list args) -{ - struct devfs_entry *dir = NULL, *de; - char buf[64]; - int error, n; - - n = vsnprintf(buf, sizeof(buf), fmt, args); - if (n >= sizeof(buf) || !buf[0]) { - printk(KERN_WARNING "%s: invalid format string %s\n", - __FUNCTION__, fmt); - return -EINVAL; - } - - de = _devfs_prepare_leaf(&dir, buf, mode); - if (!de) { - printk(KERN_WARNING "%s: could not prepare leaf for %s\n", - __FUNCTION__, buf); - return -ENOMEM; /* could be more accurate... */ - } - - de->u.dev = dev; - - error = _devfs_append_entry(dir, de, NULL); - if (error) { - printk(KERN_WARNING "%s: could not append to parent for %s\n", - __FUNCTION__, buf); - goto out; - } - - devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); - out: - devfs_put(dir); - return error; -} - -int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) -{ - va_list args; - - if (!S_ISBLK(mode)) { - printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", - __FUNCTION__, mode, fmt); - return -EINVAL; - } - - va_start(args, fmt); - return devfs_mk_dev(dev, mode, fmt, args); -} - -EXPORT_SYMBOL(devfs_mk_bdev); - -int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) -{ - va_list args; - - if (!S_ISCHR(mode)) { - printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", - __FUNCTION__, mode, fmt); - return -EINVAL; - } - - va_start(args, fmt); - return devfs_mk_dev(dev, mode, fmt, args); -} - -EXPORT_SYMBOL(devfs_mk_cdev); - -/** - * _devfs_unhook - Unhook a device entry from its parents list - * @de: The entry to unhook. - * - * Returns %TRUE if the entry was unhooked, else %FALSE if it was - * previously unhooked. - * The caller must have a write lock on the parent directory. - */ - -static int _devfs_unhook(struct devfs_entry *de) -{ - struct devfs_entry *parent; - - if (!de || (de->prev == de)) - return FALSE; - parent = de->parent; - if (de->prev == NULL) - parent->u.dir.first = de->next; - else - de->prev->next = de->next; - if (de->next == NULL) - parent->u.dir.last = de->prev; - else - de->next->prev = de->prev; - de->prev = de; /* Indicate we're unhooked */ - de->next = NULL; /* Force early termination for */ - return TRUE; -} /* End Function _devfs_unhook */ - -/** - * _devfs_unregister - Unregister a device entry from its parent. - * @dir: The parent directory. - * @de: The entry to unregister. - * - * The caller must have a write lock on the parent directory, which is - * unlocked by this function. - */ - -static void _devfs_unregister(struct devfs_entry *dir, struct devfs_entry *de) -{ - int unhooked = _devfs_unhook(de); - - write_unlock(&dir->u.dir.lock); - if (!unhooked) - return; - devfs_get(dir); - devfsd_notify(de, DEVFSD_NOTIFY_UNREGISTERED); - free_dentry(de); - devfs_put(dir); - if (!S_ISDIR(de->mode)) - return; - while (TRUE) { /* Recursively unregister: this is a stack chomper */ - struct devfs_entry *child; - - write_lock(&de->u.dir.lock); - de->u.dir.no_more_additions = TRUE; - child = de->u.dir.first; - VERIFY_ENTRY(child); - _devfs_unregister(de, child); - if (!child) - break; - DPRINTK(DEBUG_UNREGISTER, "(%s): child: %p refcount: %d\n", - child->name, child, atomic_read(&child->refcount)); - devfs_put(child); - } -} /* End Function _devfs_unregister */ - -static int devfs_do_symlink(devfs_handle_t dir, const char *name, - const char *link, devfs_handle_t * handle) -{ - int err; - unsigned int linklength; - char *newlink; - struct devfs_entry *de; - - if (handle != NULL) - *handle = NULL; - if (name == NULL) { - PRINTK("(): NULL name pointer\n"); - return -EINVAL; - } - if (link == NULL) { - PRINTK("(%s): NULL link pointer\n", name); - return -EINVAL; - } - linklength = strlen(link); - if ((newlink = kmalloc(linklength + 1, GFP_KERNEL)) == NULL) - return -ENOMEM; - memcpy(newlink, link, linklength); - newlink[linklength] = '\0'; - if ((de = _devfs_prepare_leaf(&dir, name, S_IFLNK | S_IRUGO | S_IXUGO)) - == NULL) { - PRINTK("(%s): could not prepare leaf\n", name); - kfree(newlink); - return -ENOTDIR; - } - de->info = NULL; - de->u.symlink.linkname = newlink; - de->u.symlink.length = linklength; - if ((err = _devfs_append_entry(dir, de, NULL)) != 0) { - PRINTK("(%s): could not append to parent, err: %d\n", name, - err); - devfs_put(dir); - return err; - } - devfs_put(dir); -#ifdef CONFIG_DEVFS_DEBUG - spin_lock(&stat_lock); - stat_num_bytes += linklength + 1; - spin_unlock(&stat_lock); -#endif - if (handle != NULL) - *handle = de; - return 0; -} /* End Function devfs_do_symlink */ - -/** - * devfs_mk_symlink Create a symbolic link in the devfs namespace. - * @from: The name of the entry. - * @to: Name of the destination - * - * Returns 0 on success, else a negative error code is returned. - */ - -int devfs_mk_symlink(const char *from, const char *to) -{ - devfs_handle_t de; - int err; - - err = devfs_do_symlink(NULL, from, to, &de); - if (!err) { - de->vfs = TRUE; - devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); - } - - return err; -} - -/** - * devfs_mk_dir - Create a directory in the devfs namespace. - * new name is relative to the root of the devfs. - * @fmt: The name of the entry. - * - * Use of this function is optional. The devfs_register() function - * will automatically create intermediate directories as needed. This function - * is provided for efficiency reasons, as it provides a handle to a directory. - * On failure %NULL is returned. - */ - -int devfs_mk_dir(const char *fmt, ...) -{ - struct devfs_entry *dir = NULL, *de = NULL, *old; - char buf[64]; - va_list args; - int error, n; - - va_start(args, fmt); - n = vsnprintf(buf, 64, fmt, args); - if (n >= 64 || !buf[0]) { - printk(KERN_WARNING "%s: invalid argument.", __FUNCTION__); - return -EINVAL; - } - - de = _devfs_prepare_leaf(&dir, buf, MODE_DIR); - if (!de) { - PRINTK("(%s): could not prepare leaf\n", buf); - return -EINVAL; - } - - error = _devfs_append_entry(dir, de, &old); - if (error == -EEXIST && S_ISDIR(old->mode)) { - /* - * devfs_mk_dir() of an already-existing directory will - * return success. - */ - error = 0; - goto out_put; - } else if (error) { - PRINTK("(%s): could not append to dir: %p \"%s\"\n", - buf, dir, dir->name); - devfs_put(old); - goto out_put; - } - - devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); - - out_put: - devfs_put(dir); - return error; -} - -void devfs_remove(const char *fmt, ...) -{ - char buf[64]; - va_list args; - int n; - - va_start(args, fmt); - n = vsnprintf(buf, sizeof(buf), fmt, args); - if (n < sizeof(buf) && buf[0]) { - devfs_handle_t de = _devfs_find_entry(NULL, buf, 0); - - if (!de) { - printk(KERN_ERR "%s: %s not found, cannot remove\n", - __FUNCTION__, buf); - dump_stack(); - return; - } - - write_lock(&de->parent->u.dir.lock); - _devfs_unregister(de->parent, de); - devfs_put(de); - devfs_put(de); - } -} - -/** - * devfs_generate_path - Generate a pathname for an entry, relative to the devfs root. - * @de: The devfs entry. - * @path: The buffer to write the pathname to. The pathname and '\0' - * terminator will be written at the end of the buffer. - * @buflen: The length of the buffer. - * - * Returns the offset in the buffer where the pathname starts on success, - * else a negative error code. - */ - -static int devfs_generate_path(devfs_handle_t de, char *path, int buflen) -{ - int pos; -#define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name ) - - if (de == NULL) - return -EINVAL; - VERIFY_ENTRY(de); - if (de->namelen >= buflen) - return -ENAMETOOLONG; /* Must be first */ - path[buflen - 1] = '\0'; - if (de->parent == NULL) - return buflen - 1; /* Don't prepend root */ - pos = buflen - de->namelen - 1; - memcpy(path + pos, NAMEOF(de), de->namelen); - for (de = de->parent; de->parent != NULL; de = de->parent) { - if (pos - de->namelen - 1 < 0) - return -ENAMETOOLONG; - path[--pos] = '/'; - pos -= de->namelen; - memcpy(path + pos, NAMEOF(de), de->namelen); - } - return pos; -} /* End Function devfs_generate_path */ - -/** - * devfs_setup - Process kernel boot options. - * @str: The boot options after the "devfs=". - */ - -static int __init devfs_setup(char *str) -{ - static struct { - char *name; - unsigned int mask; - unsigned int *opt; - } devfs_options_tab[] __initdata = { -#ifdef CONFIG_DEVFS_DEBUG - { - "dall", DEBUG_ALL, &devfs_debug_init}, { - "dmod", DEBUG_MODULE_LOAD, &devfs_debug_init}, { - "dreg", DEBUG_REGISTER, &devfs_debug_init}, { - "dunreg", DEBUG_UNREGISTER, &devfs_debug_init}, { - "dfree", DEBUG_FREE, &devfs_debug_init}, { - "diget", DEBUG_I_GET, &devfs_debug_init}, { - "dchange", DEBUG_SET_FLAGS, &devfs_debug_init}, { - "dsread", DEBUG_S_READ, &devfs_debug_init}, { - "dichange", DEBUG_I_CHANGE, &devfs_debug_init}, { - "dimknod", DEBUG_I_MKNOD, &devfs_debug_init}, { - "dilookup", DEBUG_I_LOOKUP, &devfs_debug_init}, { - "diunlink", DEBUG_I_UNLINK, &devfs_debug_init}, -#endif /* CONFIG_DEVFS_DEBUG */ - { - "mount", OPTION_MOUNT, &boot_options}, { - NULL, 0, NULL} - }; - - while ((*str != '\0') && !isspace(*str)) { - int i, found = 0, invert = 0; - - if (strncmp(str, "no", 2) == 0) { - invert = 1; - str += 2; - } - for (i = 0; devfs_options_tab[i].name != NULL; i++) { - int len = strlen(devfs_options_tab[i].name); - - if (strncmp(str, devfs_options_tab[i].name, len) == 0) { - if (invert) - *devfs_options_tab[i].opt &= - ~devfs_options_tab[i].mask; - else - *devfs_options_tab[i].opt |= - devfs_options_tab[i].mask; - str += len; - found = 1; - break; - } - } - if (!found) - return 0; /* No match */ - if (*str != ',') - return 0; /* No more options */ - ++str; - } - return 1; -} /* End Function devfs_setup */ - -__setup("devfs=", devfs_setup); - -EXPORT_SYMBOL(devfs_mk_dir); -EXPORT_SYMBOL(devfs_remove); - -/** - * try_modload - Notify devfsd of an inode lookup by a non-devfsd process. - * @parent: The parent devfs entry. - * @fs_info: The filesystem info. - * @name: The device name. - * @namelen: The number of characters in @name. - * @buf: A working area that will be used. This must not go out of scope - * until devfsd is idle again. - * - * Returns 0 on success (event was queued), else a negative error code. - */ - -static int try_modload(struct devfs_entry *parent, struct fs_info *fs_info, - const char *name, unsigned namelen, - struct devfs_entry *buf) -{ - if (!(fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP))) - return -ENOENT; - if (is_devfsd_or_child(fs_info)) - return -ENOENT; - memset(buf, 0, sizeof *buf); - atomic_set(&buf->refcount, 1); - buf->parent = parent; - buf->namelen = namelen; - buf->u.name = name; - WRITE_ENTRY_MAGIC(buf, MAGIC_VALUE); - if (!devfsd_notify_de(buf, DEVFSD_NOTIFY_LOOKUP, 0, - current->euid, current->egid, fs_info)) - return -ENOENT; - /* Possible success: event has been queued */ - return 0; -} /* End Function try_modload */ - -/* Superblock operations follow */ - -static struct inode_operations devfs_iops; -static struct inode_operations devfs_dir_iops; -static const struct file_operations devfs_fops; -static const struct file_operations devfs_dir_fops; -static struct inode_operations devfs_symlink_iops; - -static int devfs_notify_change(struct dentry *dentry, struct iattr *iattr) -{ - int retval; - struct devfs_entry *de; - struct inode *inode = dentry->d_inode; - struct fs_info *fs_info = inode->i_sb->s_fs_info; - - de = get_devfs_entry_from_vfs_inode(inode); - if (de == NULL) - return -ENODEV; - retval = inode_change_ok(inode, iattr); - if (retval != 0) - return retval; - retval = inode_setattr(inode, iattr); - if (retval != 0) - return retval; - DPRINTK(DEBUG_I_CHANGE, "(%d): VFS inode: %p devfs_entry: %p\n", - (int)inode->i_ino, inode, de); - DPRINTK(DEBUG_I_CHANGE, "(): mode: 0%o uid: %d gid: %d\n", - (int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid); - /* Inode is not on hash chains, thus must save permissions here rather - than in a write_inode() method */ - de->mode = inode->i_mode; - de->inode.uid = inode->i_uid; - de->inode.gid = inode->i_gid; - de->inode.atime = inode->i_atime; - de->inode.mtime = inode->i_mtime; - de->inode.ctime = inode->i_ctime; - if ((iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) && - !is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CHANGE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_notify_change */ - -static struct super_operations devfs_sops = { - .drop_inode = generic_delete_inode, - .statfs = simple_statfs, -}; - -/** - * _devfs_get_vfs_inode - Get a VFS inode. - * @sb: The super block. - * @de: The devfs inode. - * @dentry: The dentry to register with the devfs inode. - * - * Returns the inode on success, else %NULL. An implicit devfs_get() is - * performed if the inode is created. - */ - -static struct inode *_devfs_get_vfs_inode(struct super_block *sb, - struct devfs_entry *de, - struct dentry *dentry) -{ - struct inode *inode; - - if (de->prev == de) - return NULL; /* Quick check to see if unhooked */ - if ((inode = new_inode(sb)) == NULL) { - PRINTK("(%s): new_inode() failed, de: %p\n", de->name, de); - return NULL; - } - if (de->parent) { - read_lock(&de->parent->u.dir.lock); - if (de->prev != de) - de->inode.dentry = dentry; /* Not unhooked */ - read_unlock(&de->parent->u.dir.lock); - } else - de->inode.dentry = dentry; /* Root: no locking needed */ - if (de->inode.dentry != dentry) { /* Must have been unhooked */ - iput(inode); - return NULL; - } - /* FIXME where is devfs_put? */ - inode->u.generic_ip = devfs_get(de); - inode->i_ino = de->inode.ino; - DPRINTK(DEBUG_I_GET, "(%d): VFS inode: %p devfs_entry: %p\n", - (int)inode->i_ino, inode, de); - inode->i_blocks = 0; - inode->i_blksize = FAKE_BLOCK_SIZE; - inode->i_op = &devfs_iops; - inode->i_mode = de->mode; - if (S_ISDIR(de->mode)) { - inode->i_op = &devfs_dir_iops; - inode->i_fop = &devfs_dir_fops; - } else if (S_ISLNK(de->mode)) { - inode->i_op = &devfs_symlink_iops; - inode->i_size = de->u.symlink.length; - } else if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) { - init_special_inode(inode, de->mode, de->u.dev); - } else if (S_ISFIFO(de->mode) || S_ISSOCK(de->mode)) { - init_special_inode(inode, de->mode, 0); - } else { - PRINTK("(%s): unknown mode %o de: %p\n", - de->name, de->mode, de); - iput(inode); - devfs_put(de); - return NULL; - } - - inode->i_uid = de->inode.uid; - inode->i_gid = de->inode.gid; - inode->i_atime = de->inode.atime; - inode->i_mtime = de->inode.mtime; - inode->i_ctime = de->inode.ctime; - DPRINTK(DEBUG_I_GET, "(): mode: 0%o uid: %d gid: %d\n", - (int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid); - return inode; -} /* End Function _devfs_get_vfs_inode */ - -/* File operations for device entries follow */ - -static int devfs_readdir(struct file *file, void *dirent, filldir_t filldir) -{ - int err, count; - int stored = 0; - struct fs_info *fs_info; - struct devfs_entry *parent, *de, *next = NULL; - struct inode *inode = file->f_dentry->d_inode; - - fs_info = inode->i_sb->s_fs_info; - parent = get_devfs_entry_from_vfs_inode(file->f_dentry->d_inode); - if ((long)file->f_pos < 0) - return -EINVAL; - DPRINTK(DEBUG_F_READDIR, "(%s): fs_info: %p pos: %ld\n", - parent->name, fs_info, (long)file->f_pos); - switch ((long)file->f_pos) { - case 0: - err = (*filldir) (dirent, "..", 2, file->f_pos, - parent_ino(file->f_dentry), DT_DIR); - if (err == -EINVAL) - break; - if (err < 0) - return err; - file->f_pos++; - ++stored; - /* Fall through */ - case 1: - err = - (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino, - DT_DIR); - if (err == -EINVAL) - break; - if (err < 0) - return err; - file->f_pos++; - ++stored; - /* Fall through */ - default: - /* Skip entries */ - count = file->f_pos - 2; - read_lock(&parent->u.dir.lock); - for (de = parent->u.dir.first; de && (count > 0); de = de->next) - --count; - devfs_get(de); - read_unlock(&parent->u.dir.lock); - /* Now add all remaining entries */ - while (de) { - err = (*filldir) (dirent, de->name, de->namelen, - file->f_pos, de->inode.ino, - de->mode >> 12); - if (err < 0) - devfs_put(de); - else { - file->f_pos++; - ++stored; - } - if (err == -EINVAL) - break; - if (err < 0) - return err; - read_lock(&parent->u.dir.lock); - next = devfs_get(de->next); - read_unlock(&parent->u.dir.lock); - devfs_put(de); - de = next; - } - break; - } - return stored; -} /* End Function devfs_readdir */ - -/* Open devfs specific special files */ -static int devfs_open(struct inode *inode, struct file *file) -{ - int err; - int minor = MINOR(inode->i_rdev); - struct file_operations *old_fops, *new_fops; - - switch (minor) { - case 0: /* /dev/.devfsd */ - new_fops = fops_get(&devfsd_fops); - break; -#ifdef CONFIG_DEVFS_DEBUG - case 1: /* /dev/.stat */ - new_fops = fops_get(&stat_fops); - break; -#endif - default: - return -ENODEV; - } - - if (new_fops == NULL) - return -ENODEV; - old_fops = file->f_op; - file->f_op = new_fops; - err = new_fops->open ? new_fops->open(inode, file) : 0; - if (err) { - file->f_op = old_fops; - fops_put(new_fops); - } else - fops_put(old_fops); - return err; -} /* End Function devfs_open */ - -static const struct file_operations devfs_fops = { - .open = devfs_open, -}; - -static const struct file_operations devfs_dir_fops = { - .read = generic_read_dir, - .readdir = devfs_readdir, -}; - -/* Dentry operations for device entries follow */ - -/** - * devfs_d_release - Callback for when a dentry is freed. - * @dentry: The dentry. - */ - -static void devfs_d_release(struct dentry *dentry) -{ - DPRINTK(DEBUG_D_RELEASE, "(%p): inode: %p\n", dentry, dentry->d_inode); -} /* End Function devfs_d_release */ - -/** - * devfs_d_iput - Callback for when a dentry loses its inode. - * @dentry: The dentry. - * @inode: The inode. - */ - -static void devfs_d_iput(struct dentry *dentry, struct inode *inode) -{ - struct devfs_entry *de; - - de = get_devfs_entry_from_vfs_inode(inode); - DPRINTK(DEBUG_D_IPUT, - "(%s): dentry: %p inode: %p de: %p de->dentry: %p\n", de->name, - dentry, inode, de, de->inode.dentry); - if (de->inode.dentry && (de->inode.dentry != dentry)) - OOPS("(%s): de: %p dentry: %p de->dentry: %p\n", - de->name, de, dentry, de->inode.dentry); - de->inode.dentry = NULL; - iput(inode); - devfs_put(de); -} /* End Function devfs_d_iput */ - -static int devfs_d_delete(struct dentry *dentry); - -static struct dentry_operations devfs_dops = { - .d_delete = devfs_d_delete, - .d_release = devfs_d_release, - .d_iput = devfs_d_iput, -}; - -static int devfs_d_revalidate_wait(struct dentry *dentry, struct nameidata *); - -static struct dentry_operations devfs_wait_dops = { - .d_delete = devfs_d_delete, - .d_release = devfs_d_release, - .d_iput = devfs_d_iput, - .d_revalidate = devfs_d_revalidate_wait, -}; - -/** - * devfs_d_delete - Callback for when all files for a dentry are closed. - * @dentry: The dentry. - */ - -static int devfs_d_delete(struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - - if (dentry->d_op == &devfs_wait_dops) - dentry->d_op = &devfs_dops; - /* Unhash dentry if negative (has no inode) */ - if (inode == NULL) { - DPRINTK(DEBUG_D_DELETE, "(%p): dropping negative dentry\n", - dentry); - return 1; - } - return 0; -} /* End Function devfs_d_delete */ - -struct devfs_lookup_struct { - devfs_handle_t de; - wait_queue_head_t wait_queue; -}; - -/* XXX: this doesn't handle the case where we got a negative dentry - but a devfs entry has been registered in the meanwhile */ -static int devfs_d_revalidate_wait(struct dentry *dentry, struct nameidata *nd) -{ - struct inode *dir = dentry->d_parent->d_inode; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - devfs_handle_t parent = get_devfs_entry_from_vfs_inode(dir); - struct devfs_lookup_struct *lookup_info = dentry->d_fsdata; - DECLARE_WAITQUEUE(wait, current); - int need_lock; - - /* - * FIXME HACK - * - * make sure that - * d_instantiate always runs under lock - * we release i_mutex lock before going to sleep - * - * unfortunately sometimes d_revalidate is called with - * and sometimes without i_mutex lock held. The following checks - * attempt to deduce when we need to add (and drop resp.) lock - * here. This relies on current (2.6.2) calling coventions: - * - * lookup_hash is always run under i_mutex and is passing NULL - * as nd - * - * open(...,O_CREATE,...) calls _lookup_hash under i_mutex - * and sets flags to LOOKUP_OPEN|LOOKUP_CREATE - * - * all other invocations of ->d_revalidate seem to happen - * outside of i_mutex - */ - need_lock = nd && - (!(nd->flags & LOOKUP_CREATE) || (nd->flags & LOOKUP_PARENT)); - - if (need_lock) - mutex_lock(&dir->i_mutex); - - if (is_devfsd_or_child(fs_info)) { - devfs_handle_t de = lookup_info->de; - struct inode *inode; - - DPRINTK(DEBUG_I_LOOKUP, - "(%s): dentry: %p inode: %p de: %p by: \"%s\"\n", - dentry->d_name.name, dentry, dentry->d_inode, de, - current->comm); - if (dentry->d_inode) - goto out; - if (de == NULL) { - read_lock(&parent->u.dir.lock); - de = _devfs_search_dir(parent, dentry->d_name.name, - dentry->d_name.len); - read_unlock(&parent->u.dir.lock); - if (de == NULL) - goto out; - lookup_info->de = de; - } - /* Create an inode, now that the driver information is available */ - inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry); - if (!inode) - goto out; - DPRINTK(DEBUG_I_LOOKUP, - "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n", - de->name, de->inode.ino, inode, de, current->comm); - d_instantiate(dentry, inode); - goto out; - } - if (lookup_info == NULL) - goto out; /* Early termination */ - read_lock(&parent->u.dir.lock); - if (dentry->d_fsdata) { - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&lookup_info->wait_queue, &wait); - read_unlock(&parent->u.dir.lock); - /* at this point it is always (hopefully) locked */ - mutex_unlock(&dir->i_mutex); - schedule(); - mutex_lock(&dir->i_mutex); - /* - * This does not need nor should remove wait from wait_queue. - * Wait queue head is never reused - nothing is ever added to it - * after all waiters have been waked up and head itself disappears - * very soon after it. Moreover it is local variable on stack that - * is likely to have already disappeared so any reference to it - * at this point is buggy. - */ - - } else - read_unlock(&parent->u.dir.lock); - - out: - if (need_lock) - mutex_unlock(&dir->i_mutex); - return 1; -} /* End Function devfs_d_revalidate_wait */ - -/* Inode operations for device entries follow */ - -static struct dentry *devfs_lookup(struct inode *dir, struct dentry *dentry, - struct nameidata *nd) -{ - struct devfs_entry tmp; /* Must stay in scope until devfsd idle again */ - struct devfs_lookup_struct lookup_info; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - struct dentry *retval = NULL; - - /* Set up the dentry operations before anything else, to ensure cleaning - up on any error */ - dentry->d_op = &devfs_dops; - /* First try to get the devfs entry for this directory */ - parent = get_devfs_entry_from_vfs_inode(dir); - DPRINTK(DEBUG_I_LOOKUP, "(%s): dentry: %p parent: %p by: \"%s\"\n", - dentry->d_name.name, dentry, parent, current->comm); - if (parent == NULL) - return ERR_PTR(-ENOENT); - read_lock(&parent->u.dir.lock); - de = _devfs_search_dir(parent, dentry->d_name.name, dentry->d_name.len); - read_unlock(&parent->u.dir.lock); - lookup_info.de = de; - init_waitqueue_head(&lookup_info.wait_queue); - dentry->d_fsdata = &lookup_info; - if (de == NULL) { /* Try with devfsd. For any kind of failure, leave a negative dentry - so someone else can deal with it (in the case where the sysadmin - does a mknod()). It's important to do this before hashing the - dentry, so that the devfsd queue is filled before revalidates - can start */ - if (try_modload(parent, fs_info, dentry->d_name.name, dentry->d_name.len, &tmp) < 0) { /* Lookup event was not queued to devfsd */ - d_add(dentry, NULL); - return NULL; - } - } - dentry->d_op = &devfs_wait_dops; - d_add(dentry, NULL); /* Open the floodgates */ - /* Unlock directory semaphore, which will release any waiters. They - will get the hashed dentry, and may be forced to wait for - revalidation */ - mutex_unlock(&dir->i_mutex); - wait_for_devfsd_finished(fs_info); /* If I'm not devfsd, must wait */ - mutex_lock(&dir->i_mutex); /* Grab it again because them's the rules */ - de = lookup_info.de; - /* If someone else has been so kind as to make the inode, we go home - early */ - if (dentry->d_inode) - goto out; - if (de == NULL) { - read_lock(&parent->u.dir.lock); - de = _devfs_search_dir(parent, dentry->d_name.name, - dentry->d_name.len); - read_unlock(&parent->u.dir.lock); - if (de == NULL) - goto out; - /* OK, there's an entry now, but no VFS inode yet */ - } - /* Create an inode, now that the driver information is available */ - inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry); - if (!inode) { - retval = ERR_PTR(-ENOMEM); - goto out; - } - DPRINTK(DEBUG_I_LOOKUP, - "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n", de->name, - de->inode.ino, inode, de, current->comm); - d_instantiate(dentry, inode); - out: - write_lock(&parent->u.dir.lock); - dentry->d_op = &devfs_dops; - dentry->d_fsdata = NULL; - wake_up(&lookup_info.wait_queue); - write_unlock(&parent->u.dir.lock); - devfs_put(de); - return retval; -} /* End Function devfs_lookup */ - -static int devfs_unlink(struct inode *dir, struct dentry *dentry) -{ - int unhooked; - struct devfs_entry *de; - struct inode *inode = dentry->d_inode; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - - de = get_devfs_entry_from_vfs_inode(inode); - DPRINTK(DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de); - if (de == NULL) - return -ENOENT; - if (!de->vfs) - return -EPERM; - write_lock(&de->parent->u.dir.lock); - unhooked = _devfs_unhook(de); - write_unlock(&de->parent->u.dir.lock); - if (!unhooked) - return -ENOENT; - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_DELETE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - free_dentry(de); - devfs_put(de); - return 0; -} /* End Function devfs_unlink */ - -static int devfs_symlink(struct inode *dir, struct dentry *dentry, - const char *symname) -{ - int err; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - - /* First try to get the devfs entry for this directory */ - parent = get_devfs_entry_from_vfs_inode(dir); - if (parent == NULL) - return -ENOENT; - err = devfs_do_symlink(parent, dentry->d_name.name, symname, &de); - DPRINTK(DEBUG_DISABLED, "(%s): errcode from : %d\n", - dentry->d_name.name, err); - if (err < 0) - return err; - de->vfs = TRUE; - de->inode.uid = current->euid; - de->inode.gid = current->egid; - de->inode.atime = CURRENT_TIME; - de->inode.mtime = CURRENT_TIME; - de->inode.ctime = CURRENT_TIME; - if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL) - return -ENOMEM; - DPRINTK(DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n", - dentry->d_name.name, de->inode.ino, inode, dentry); - d_instantiate(dentry, inode); - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_symlink */ - -static int devfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -{ - int err; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - - mode = (mode & ~S_IFMT) | S_IFDIR; /* VFS doesn't pass S_IFMT part */ - parent = get_devfs_entry_from_vfs_inode(dir); - if (parent == NULL) - return -ENOENT; - de = _devfs_alloc_entry(dentry->d_name.name, dentry->d_name.len, mode); - if (!de) - return -ENOMEM; - de->vfs = TRUE; - if ((err = _devfs_append_entry(parent, de, NULL)) != 0) - return err; - de->inode.uid = current->euid; - de->inode.gid = current->egid; - de->inode.atime = CURRENT_TIME; - de->inode.mtime = CURRENT_TIME; - de->inode.ctime = CURRENT_TIME; - if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL) - return -ENOMEM; - DPRINTK(DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n", - dentry->d_name.name, de->inode.ino, inode, dentry); - d_instantiate(dentry, inode); - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_mkdir */ - -static int devfs_rmdir(struct inode *dir, struct dentry *dentry) -{ - int err = 0; - struct devfs_entry *de; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct inode *inode = dentry->d_inode; - - if (dir->i_sb->s_fs_info != inode->i_sb->s_fs_info) - return -EINVAL; - de = get_devfs_entry_from_vfs_inode(inode); - if (de == NULL) - return -ENOENT; - if (!S_ISDIR(de->mode)) - return -ENOTDIR; - if (!de->vfs) - return -EPERM; - /* First ensure the directory is empty and will stay that way */ - write_lock(&de->u.dir.lock); - if (de->u.dir.first) - err = -ENOTEMPTY; - else - de->u.dir.no_more_additions = TRUE; - write_unlock(&de->u.dir.lock); - if (err) - return err; - /* Now unhook the directory from its parent */ - write_lock(&de->parent->u.dir.lock); - if (!_devfs_unhook(de)) - err = -ENOENT; - write_unlock(&de->parent->u.dir.lock); - if (err) - return err; - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_DELETE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - free_dentry(de); - devfs_put(de); - return 0; -} /* End Function devfs_rmdir */ - -static int devfs_mknod(struct inode *dir, struct dentry *dentry, int mode, - dev_t rdev) -{ - int err; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - - DPRINTK(DEBUG_I_MKNOD, "(%s): mode: 0%o dev: %u:%u\n", - dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); - parent = get_devfs_entry_from_vfs_inode(dir); - if (parent == NULL) - return -ENOENT; - de = _devfs_alloc_entry(dentry->d_name.name, dentry->d_name.len, mode); - if (!de) - return -ENOMEM; - de->vfs = TRUE; - if (S_ISCHR(mode) || S_ISBLK(mode)) - de->u.dev = rdev; - if ((err = _devfs_append_entry(parent, de, NULL)) != 0) - return err; - de->inode.uid = current->euid; - de->inode.gid = current->egid; - de->inode.atime = CURRENT_TIME; - de->inode.mtime = CURRENT_TIME; - de->inode.ctime = CURRENT_TIME; - if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL) - return -ENOMEM; - DPRINTK(DEBUG_I_MKNOD, ": new VFS inode(%u): %p dentry: %p\n", - de->inode.ino, inode, dentry); - d_instantiate(dentry, inode); - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_mknod */ - -static void *devfs_follow_link(struct dentry *dentry, struct nameidata *nd) -{ - struct devfs_entry *p = get_devfs_entry_from_vfs_inode(dentry->d_inode); - nd_set_link(nd, p ? p->u.symlink.linkname : ERR_PTR(-ENODEV)); - return NULL; -} /* End Function devfs_follow_link */ - -static struct inode_operations devfs_iops = { - .setattr = devfs_notify_change, -}; - -static struct inode_operations devfs_dir_iops = { - .lookup = devfs_lookup, - .unlink = devfs_unlink, - .symlink = devfs_symlink, - .mkdir = devfs_mkdir, - .rmdir = devfs_rmdir, - .mknod = devfs_mknod, - .setattr = devfs_notify_change, -}; - -static struct inode_operations devfs_symlink_iops = { - .readlink = generic_readlink, - .follow_link = devfs_follow_link, - .setattr = devfs_notify_change, -}; - -static int devfs_fill_super(struct super_block *sb, void *data, int silent) -{ - struct inode *root_inode = NULL; - - if (_devfs_get_root_entry() == NULL) - goto out_no_root; - atomic_set(&fs_info.devfsd_overrun_count, 0); - init_waitqueue_head(&fs_info.devfsd_wait_queue); - init_waitqueue_head(&fs_info.revalidate_wait_queue); - fs_info.sb = sb; - sb->s_fs_info = &fs_info; - sb->s_blocksize = 1024; - sb->s_blocksize_bits = 10; - sb->s_magic = DEVFS_SUPER_MAGIC; - sb->s_op = &devfs_sops; - sb->s_time_gran = 1; - if ((root_inode = _devfs_get_vfs_inode(sb, root_entry, NULL)) == NULL) - goto out_no_root; - sb->s_root = d_alloc_root(root_inode); - if (!sb->s_root) - goto out_no_root; - DPRINTK(DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->s_fs_info); - return 0; - - out_no_root: - PRINTK("(): get root inode failed\n"); - if (root_inode) - iput(root_inode); - return -EINVAL; -} /* End Function devfs_fill_super */ - -static int devfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data, struct vfsmount *mnt) -{ - return get_sb_single(fs_type, flags, data, devfs_fill_super, mnt); -} - -static struct file_system_type devfs_fs_type = { - .name = DEVFS_NAME, - .get_sb = devfs_get_sb, - .kill_sb = kill_anon_super, -}; - -/* File operations for devfsd follow */ - -static ssize_t devfsd_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos) -{ - int done = FALSE; - int ival; - loff_t pos, devname_offset, tlen, rpos; - devfs_handle_t de; - struct devfsd_buf_entry *entry; - struct fs_info *fs_info = file->f_dentry->d_inode->i_sb->s_fs_info; - struct devfsd_notify_struct *info = fs_info->devfsd_info; - DECLARE_WAITQUEUE(wait, current); - - /* Verify the task has grabbed the queue */ - if (fs_info->devfsd_task != current) - return -EPERM; - info->major = 0; - info->minor = 0; - /* Block for a new entry */ - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&fs_info->devfsd_wait_queue, &wait); - while (devfsd_queue_empty(fs_info)) { - fs_info->devfsd_sleeping = TRUE; - wake_up(&fs_info->revalidate_wait_queue); - schedule(); - fs_info->devfsd_sleeping = FALSE; - if (signal_pending(current)) { - remove_wait_queue(&fs_info->devfsd_wait_queue, &wait); - __set_current_state(TASK_RUNNING); - return -EINTR; - } - set_current_state(TASK_INTERRUPTIBLE); - } - remove_wait_queue(&fs_info->devfsd_wait_queue, &wait); - __set_current_state(TASK_RUNNING); - /* Now play with the data */ - ival = atomic_read(&fs_info->devfsd_overrun_count); - info->overrun_count = ival; - entry = fs_info->devfsd_first_event; - info->type = entry->type; - info->mode = entry->mode; - info->uid = entry->uid; - info->gid = entry->gid; - de = entry->de; - if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) { - info->major = MAJOR(de->u.dev); - info->minor = MINOR(de->u.dev); - } - pos = devfs_generate_path(de, info->devname, DEVFS_PATHLEN); - if (pos < 0) - return pos; - info->namelen = DEVFS_PATHLEN - pos - 1; - if (info->mode == 0) - info->mode = de->mode; - devname_offset = info->devname - (char *)info; - rpos = *ppos; - if (rpos < devname_offset) { - /* Copy parts of the header */ - tlen = devname_offset - rpos; - if (tlen > len) - tlen = len; - if (copy_to_user(buf, (char *)info + rpos, tlen)) { - return -EFAULT; - } - rpos += tlen; - buf += tlen; - len -= tlen; - } - if ((rpos >= devname_offset) && (len > 0)) { - /* Copy the name */ - tlen = info->namelen + 1; - if (tlen > len) - tlen = len; - else - done = TRUE; - if (copy_to_user - (buf, info->devname + pos + rpos - devname_offset, tlen)) { - return -EFAULT; - } - rpos += tlen; - } - tlen = rpos - *ppos; - if (done) { - devfs_handle_t parent; - - spin_lock(&fs_info->devfsd_buffer_lock); - fs_info->devfsd_first_event = entry->next; - if (entry->next == NULL) - fs_info->devfsd_last_event = NULL; - spin_unlock(&fs_info->devfsd_buffer_lock); - for (; de != NULL; de = parent) { - parent = de->parent; - devfs_put(de); - } - kmem_cache_free(devfsd_buf_cache, entry); - if (ival > 0) - atomic_sub(ival, &fs_info->devfsd_overrun_count); - *ppos = 0; - } else - *ppos = rpos; - return tlen; -} /* End Function devfsd_read */ - -static int devfsd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int ival; - struct fs_info *fs_info = inode->i_sb->s_fs_info; - - switch (cmd) { - case DEVFSDIOC_GET_PROTO_REV: - ival = DEVFSD_PROTOCOL_REVISION_KERNEL; - if (copy_to_user((void __user *)arg, &ival, sizeof ival)) - return -EFAULT; - break; - case DEVFSDIOC_SET_EVENT_MASK: - /* Ensure only one reader has access to the queue. This scheme will - work even if the global kernel lock were to be removed, because it - doesn't matter who gets in first, as long as only one gets it */ - if (fs_info->devfsd_task == NULL) { - static DEFINE_SPINLOCK(lock); - - if (!spin_trylock(&lock)) - return -EBUSY; - if (fs_info->devfsd_task != NULL) { /* We lost the race... */ - spin_unlock(&lock); - return -EBUSY; - } - fs_info->devfsd_task = current; - spin_unlock(&lock); - fs_info->devfsd_pgrp = - (process_group(current) == - current->pid) ? process_group(current) : 0; - fs_info->devfsd_file = file; - fs_info->devfsd_info = - kmalloc(sizeof *fs_info->devfsd_info, GFP_KERNEL); - if (!fs_info->devfsd_info) { - devfsd_close(inode, file); - return -ENOMEM; - } - } else if (fs_info->devfsd_task != current) - return -EBUSY; - fs_info->devfsd_event_mask = arg; /* Let the masses come forth */ - break; - case DEVFSDIOC_RELEASE_EVENT_QUEUE: - if (fs_info->devfsd_file != file) - return -EPERM; - return devfsd_close(inode, file); - /*break; */ -#ifdef CONFIG_DEVFS_DEBUG - case DEVFSDIOC_SET_DEBUG_MASK: - if (copy_from_user(&ival, (void __user *)arg, sizeof ival)) - return -EFAULT; - devfs_debug = ival; - break; -#endif - default: - return -ENOIOCTLCMD; - } - return 0; -} /* End Function devfsd_ioctl */ - -static int devfsd_close(struct inode *inode, struct file *file) -{ - struct devfsd_buf_entry *entry, *next; - struct fs_info *fs_info = inode->i_sb->s_fs_info; - - if (fs_info->devfsd_file != file) - return 0; - fs_info->devfsd_event_mask = 0; - fs_info->devfsd_file = NULL; - spin_lock(&fs_info->devfsd_buffer_lock); - entry = fs_info->devfsd_first_event; - fs_info->devfsd_first_event = NULL; - fs_info->devfsd_last_event = NULL; - kfree(fs_info->devfsd_info); - fs_info->devfsd_info = NULL; - spin_unlock(&fs_info->devfsd_buffer_lock); - fs_info->devfsd_pgrp = 0; - fs_info->devfsd_task = NULL; - wake_up(&fs_info->revalidate_wait_queue); - for (; entry; entry = next) { - next = entry->next; - kmem_cache_free(devfsd_buf_cache, entry); - } - return 0; -} /* End Function devfsd_close */ - -#ifdef CONFIG_DEVFS_DEBUG -static ssize_t stat_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos) -{ - ssize_t num; - char txt[80]; - - num = sprintf(txt, "Number of entries: %u number of bytes: %u\n", - stat_num_entries, stat_num_bytes) + 1; - if (*ppos >= num) - return 0; - if (*ppos + len > num) - len = num - *ppos; - if (copy_to_user(buf, txt + *ppos, len)) - return -EFAULT; - *ppos += len; - return len; -} /* End Function stat_read */ -#endif - -static int __init init_devfs_fs(void) -{ - int err; - int major; - struct devfs_entry *devfsd; -#ifdef CONFIG_DEVFS_DEBUG - struct devfs_entry *stat; -#endif - - if (_devfs_get_root_entry() == NULL) - return -ENOMEM; - - printk(KERN_INFO "%s: %s Richard Gooch (rgooch@atnf.csiro.au)\n", - DEVFS_NAME, DEVFS_VERSION); - devfsd_buf_cache = kmem_cache_create("devfsd_event", - sizeof(struct devfsd_buf_entry), - 0, 0, NULL, NULL); - if (!devfsd_buf_cache) - OOPS("(): unable to allocate event slab\n"); -#ifdef CONFIG_DEVFS_DEBUG - devfs_debug = devfs_debug_init; - printk(KERN_INFO "%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug); -#endif - printk(KERN_INFO "%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options); - - /* register special device for devfsd communication */ - major = register_chrdev(0, "devfs", &devfs_fops); - if (major < 0) - return major; - - /* And create the entry for ".devfsd" */ - devfsd = _devfs_alloc_entry(".devfsd", 0, S_IFCHR | S_IRUSR | S_IWUSR); - if (devfsd == NULL) - return -ENOMEM; - devfsd->u.dev = MKDEV(major, 0); - _devfs_append_entry(root_entry, devfsd, NULL); - -#ifdef CONFIG_DEVFS_DEBUG - stat = _devfs_alloc_entry(".stat", 0, S_IFCHR | S_IRUGO); - if (stat == NULL) - return -ENOMEM; - stat->u.dev = MKDEV(major, 1); - _devfs_append_entry(root_entry, stat, NULL); -#endif - - err = register_filesystem(&devfs_fs_type); - return err; -} /* End Function init_devfs_fs */ - -void __init mount_devfs_fs(void) -{ - int err; - - if (!(boot_options & OPTION_MOUNT)) - return; - err = do_mount("none", "/dev", "devfs", 0, NULL); - if (err == 0) - printk(KERN_INFO "Mounted devfs on /dev\n"); - else - PRINTK("(): unable to mount devfs, err: %d\n", err); -} /* End Function mount_devfs_fs */ - -module_init(init_devfs_fs) diff --git a/fs/devfs/util.c b/fs/devfs/util.c deleted file mode 100644 index db06d388c9ac..000000000000 --- a/fs/devfs/util.c +++ /dev/null @@ -1,97 +0,0 @@ -/* devfs (Device FileSystem) utilities. - - Copyright (C) 1999-2002 Richard Gooch - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Richard Gooch may be reached by email at rgooch@atnf.csiro.au - The postal address is: - Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. - - ChangeLog - - 19991031 Richard Gooch - Created. - 19991103 Richard Gooch - Created <_devfs_convert_name> and supported SCSI and IDE CD-ROMs - 20000203 Richard Gooch - Changed operations pointer type to void *. - 20000621 Richard Gooch - Changed interface to . - 20000622 Richard Gooch - Took account of interface change to . - Took account of interface change to . - 20010519 Richard Gooch - Documentation cleanup. - 20010709 Richard Gooch - Created and . - 20010710 Richard Gooch - Created . - 20010730 Richard Gooch - Documentation typo fix. - 20010806 Richard Gooch - Made and private. - 20010813 Richard Gooch - Fixed bug in : limited to 128 numbers - 20010818 Richard Gooch - Updated major masks up to Linus' "no new majors" proclamation. - Block: were 126 now 122 free, char: were 26 now 19 free. - 20020324 Richard Gooch - Fixed bug in : was clearing beyond - bitfield. - 20020326 Richard Gooch - Fixed bitfield data type for . - Made major bitfield type and initialiser 64 bit safe. - 20020413 Richard Gooch - Fixed shift warning on 64 bit machines. - 20020428 Richard Gooch - Copied and used macro for error messages from fs/devfs/base.c - 20021013 Richard Gooch - Documentation fix. - 20030101 Adam J. Richter - Eliminate DEVFS_SPECIAL_{CHR,BLK}. Use mode_t instead. - 20030106 Christoph Hellwig - Rewrite devfs_{,de}alloc_devnum to look like C code. -*/ -#include -#include -#include -#include -#include -#include -#include - -int devfs_register_tape(const char *name) -{ - char tname[32], dest[64]; - static unsigned int tape_counter; - unsigned int n = tape_counter++; - - sprintf(dest, "../%s", name); - sprintf(tname, "tapes/tape%u", n); - devfs_mk_symlink(tname, dest); - - return n; -} - -EXPORT_SYMBOL(devfs_register_tape); - -void devfs_unregister_tape(int num) -{ - if (num >= 0) - devfs_remove("tapes/tape%u", num); -} - -EXPORT_SYMBOL(devfs_unregister_tape); diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index 917d62e41480..269d000bb2a3 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -567,11 +567,6 @@ COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER) COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST) COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST) COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT) -/* DEVFS */ -COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV) -COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK) -COMPATIBLE_IOCTL(DEVFSDIOC_RELEASE_EVENT_QUEUE) -COMPATIBLE_IOCTL(DEVFSDIOC_SET_DEBUG_MASK) /* Raw devices */ COMPATIBLE_IOCTL(RAW_SETBIND) COMPATIBLE_IOCTL(RAW_GETBIND) diff --git a/include/linux/devfs_fs.h b/include/linux/devfs_fs.h deleted file mode 100644 index de236f431877..000000000000 --- a/include/linux/devfs_fs.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _LINUX_DEVFS_FS_H -#define _LINUX_DEVFS_FS_H - -#include - -#define DEVFSD_PROTOCOL_REVISION_KERNEL 5 - -#define DEVFSD_IOCTL_BASE 'd' - -/* These are the various ioctls */ -#define DEVFSDIOC_GET_PROTO_REV _IOR(DEVFSD_IOCTL_BASE, 0, int) -#define DEVFSDIOC_SET_EVENT_MASK _IOW(DEVFSD_IOCTL_BASE, 2, int) -#define DEVFSDIOC_RELEASE_EVENT_QUEUE _IOW(DEVFSD_IOCTL_BASE, 3, int) -#define DEVFSDIOC_SET_DEBUG_MASK _IOW(DEVFSD_IOCTL_BASE, 4, int) - -#define DEVFSD_NOTIFY_REGISTERED 0 -#define DEVFSD_NOTIFY_UNREGISTERED 1 -#define DEVFSD_NOTIFY_ASYNC_OPEN 2 -#define DEVFSD_NOTIFY_CLOSE 3 -#define DEVFSD_NOTIFY_LOOKUP 4 -#define DEVFSD_NOTIFY_CHANGE 5 -#define DEVFSD_NOTIFY_CREATE 6 -#define DEVFSD_NOTIFY_DELETE 7 - -#define DEVFS_PATHLEN 1024 /* Never change this otherwise the - binary interface will change */ - -struct devfsd_notify_struct { /* Use native C types to ensure same types in kernel and user space */ - unsigned int type; /* DEVFSD_NOTIFY_* value */ - unsigned int mode; /* Mode of the inode or device entry */ - unsigned int major; /* Major number of device entry */ - unsigned int minor; /* Minor number of device entry */ - unsigned int uid; /* Uid of process, inode or device entry */ - unsigned int gid; /* Gid of process, inode or device entry */ - unsigned int overrun_count; /* Number of lost events */ - unsigned int namelen; /* Number of characters not including '\0' */ - /* The device name MUST come last */ - char devname[DEVFS_PATHLEN]; /* This will be '\0' terminated */ -}; - -#endif /* _LINUX_DEVFS_FS_H */ diff --git a/include/linux/devfs_fs_kernel.h b/include/linux/devfs_fs_kernel.h index 0d74a6f22abc..ef34d7ffe49d 100644 --- a/include/linux/devfs_fs_kernel.h +++ b/include/linux/devfs_fs_kernel.h @@ -4,25 +4,8 @@ #include #include #include - #include -#define DEVFS_SUPER_MAGIC 0x1373 - -#ifdef CONFIG_DEVFS_FS -extern int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) - __attribute__ ((format(printf, 3, 4))); -extern int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) - __attribute__ ((format(printf, 3, 4))); -extern int devfs_mk_symlink(const char *name, const char *link); -extern int devfs_mk_dir(const char *fmt, ...) - __attribute__ ((format(printf, 1, 2))); -extern void devfs_remove(const char *fmt, ...) - __attribute__ ((format(printf, 1, 2))); -extern int devfs_register_tape(const char *name); -extern void devfs_unregister_tape(int num); -extern void mount_devfs_fs(void); -#else /* CONFIG_DEVFS_FS */ static inline int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) { return 0; @@ -53,5 +36,4 @@ static inline void mount_devfs_fs(void) { return; } -#endif /* CONFIG_DEVFS_FS */ #endif /* _LINUX_DEVFS_FS_KERNEL_H */ From 5c3927dc3468f47b803c9e1bb82cbed2bbd411ab Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2005 21:15:16 -0700 Subject: [PATCH 037/556] [PATCH] devfs: Remove devfs documentation from the kernel tree Removes the Documentaiton/filesystems/devfs/ directory Signed-off-by: Greg Kroah-Hartman --- Documentation/filesystems/devfs/ChangeLog | 1977 ------------------ Documentation/filesystems/devfs/README | 1959 ----------------- Documentation/filesystems/devfs/ToDo | 40 - Documentation/filesystems/devfs/boot-options | 65 - 4 files changed, 4041 deletions(-) delete mode 100644 Documentation/filesystems/devfs/ChangeLog delete mode 100644 Documentation/filesystems/devfs/README delete mode 100644 Documentation/filesystems/devfs/ToDo delete mode 100644 Documentation/filesystems/devfs/boot-options diff --git a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog deleted file mode 100644 index e5aba5246d7c..000000000000 --- a/Documentation/filesystems/devfs/ChangeLog +++ /dev/null @@ -1,1977 +0,0 @@ -/* -*- auto-fill -*- */ -=============================================================================== -Changes for patch v1 - -- creation of devfs - -- modified miscellaneous character devices to support devfs -=============================================================================== -Changes for patch v2 - -- bug fix with manual inode creation -=============================================================================== -Changes for patch v3 - -- bugfixes - -- documentation improvements - -- created a couple of scripts (one to save&restore a devfs and the - other to set up compatibility symlinks) - -- devfs support for SCSI discs. New name format is: sd_hHcCiIlL -=============================================================================== -Changes for patch v4 - -- bugfix for the directory reading code - -- bugfix for compilation with kerneld - -- devfs support for generic hard discs - -- rationalisation of the various watchdog drivers -=============================================================================== -Changes for patch v5 - -- support for mounting directly from entries in the devfs (it doesn't - need to be mounted to do this), including the root filesystem. - Mounting of swap partitions also works. Hence, now if you set - CONFIG_DEVFS_ONLY to 'Y' then you won't be able to access your discs - via ordinary device nodes. Naturally, the default is 'N' so that you - can still use your old device nodes. If you want to mount from devfs - entries, make sure you use: append = "root=/dev/sd_..." in your - lilo.conf. It seems LILO looks for the device number (major&minor) - and writes that into the kernel image :-( - -- support for character memory devices (/dev/null, /dev/zero, /dev/full - and so on). Thanks to C. Scott Ananian -=============================================================================== -Changes for patch v6 - -- support for subdirectories - -- support for symbolic links (created by devfs_mk_symlink(), no - support yet for creation via symlink(2)) - -- SCSI disc naming now cast in stone, with the format: - /dev/sd/c0b1t2u3 controller=0, bus=1, ID=2, LUN=3, whole disc - /dev/sd/c0b1t2u3p4 controller=0, bus=1, ID=2, LUN=3, 4th partition - -- loop devices now appear in devfs - -- tty devices, console, serial ports, etc. now appear in devfs - Thanks to C. Scott Ananian - -- bugs with mounting devfs-only devices now fixed -=============================================================================== -Changes for patch v7 - -- SCSI CD-ROMS, tapes and generic devices now appear in devfs -=============================================================================== -Changes for patch v8 - -- bugfix with no-rewind SCSI tapes - -- RAMDISCs now appear in devfs - -- better cleaning up of devfs entries created by various modules - -- interface change to -=============================================================================== -Changes for patch v9 - -- the v8 patch was corrupted somehow, which would affect the patch for - linux/fs/filesystems.c - I've also fixed the v8 patch file on the WWW - -- MetaDevices (/dev/md*) should now appear in devfs -=============================================================================== -Changes for patch v10 - -- bugfix in meta device support for devfs - -- created this ChangeLog file - -- added devfs support to the floppy driver - -- added support for creating sockets in a devfs -=============================================================================== -Changes for patch v11 - -- added DEVFS_FL_HIDE_UNREG flag - -- incorporated better patch for ttyname() in libc 5.4.43 from H.J. Lu. - -- interface change to - -- support for creating symlinks with symlink(2) - -- parallel port printer (/dev/lp*) now appears in devfs -=============================================================================== -Changes for patch v12 - -- added inode check to function - -- improved devfs support when mounting from devfs - -- added call to <> operation when removing swap areas on - devfs devices - -- increased NR_SUPER to 128 to support large numbers of devfs mounts - (for chroot(2) gaols) - -- fixed bug in SCSI disc support: was generating incorrect minors if - SCSI ID's did not start at 0 and increase by 1 - -- support symlink traversal when mounting root -=============================================================================== -Changes for patch v13 - -- added devfs support to soundcard driver - Thanks to Eric Dumas and - C. Scott Ananian - -- added devfs support to the joystick driver - -- loop driver now has it's own subdirectory "/dev/loop/" - -- created and functions - -- fix problem with SCSI disc compatibility names (sd{a,b,c,d,e,f}) - which assumes ID's start at 0 and increase by 1. Also only create - devfs entries for SCSI disc partitions which actually exist - Show new names in partition check - Thanks to Jakub Jelinek -=============================================================================== -Changes for patch v14 - -- bug fix in floppy driver: would not compile without - CONFIG_DEVFS_FS='Y' - Thanks to Jurgen Botz - -- bug fix in loop driver - Thanks to C. Scott Ananian - -- do not create devfs entries for printers not configured - Thanks to C. Scott Ananian - -- do not create devfs entries for serial ports not present - Thanks to C. Scott Ananian - -- ensure is exported from tty_io.c - Thanks to C. Scott Ananian - -- allow unregistering of devfs symlink entries - -- fixed bug in SCSI disc naming introduced in last patch version -=============================================================================== -Changes for patch v15 - -- ported to kernel 2.1.81 -=============================================================================== -Changes for patch v16 - -- created function - -- moved DEVFS_SUPER_MAGIC into header file - -- added DEVFS_FL_HIDE flag - -- created - -- created - -- fixed bugs in searching by major&minor - -- changed interface to , and - - -- fixed inode times when symlink created with symlink(2) - -- change tty driver to do auto-creation of devfs entries - Thanks to C. Scott Ananian - -- fixed bug in genhd.c: whole disc (non-SCSI) was not registered to - devfs - -- updated libc 5.4.43 patch for ttyname() -=============================================================================== -Changes for patch v17 - -- added CONFIG_DEVFS_TTY_COMPAT - Thanks to C. Scott Ananian - -- bugfix in devfs support for drivers/char/lp.c - Thanks to C. Scott Ananian - -- clean up serial driver so that PCMCIA devices unregister correctly - Thanks to C. Scott Ananian - -- fixed bug in genhd.c: whole disc (non-SCSI) was not registered to - devfs [was missing in patch v16] - -- updated libc 5.4.43 patch for ttyname() [was missing in patch v16] - -- all SCSI devices now registered in /dev/sg - -- support removal of devfs entries via unlink(2) -=============================================================================== -Changes for patch v18 - -- added floppy/?u720 floppy entry - -- fixed kerneld support for entries in devfs subdirectories - -- incorporated latest patch for ttyname() in libc 5.4.43 from H.J. Lu. -=============================================================================== -Changes for patch v19 - -- bug fix when looking up unregistered entries: kerneld was not called - -- fixes for kernel 2.1.86 (now requires 2.1.86) -=============================================================================== -Changes for patch v20 - -- only create available floppy entries - Thanks to Andrzej Krzysztofowicz - -- new IDE naming scheme following SCSI format (i.e. /dev/id/c0b0t0u0p1 - instead of /dev/hda1) - Thanks to Andrzej Krzysztofowicz - -- new XT disc naming scheme following SCSI format (i.e. /dev/xd/c0t0p1 - instead of /dev/xda1) - Thanks to Andrzej Krzysztofowicz - -- new non-standard CD-ROM names (i.e. /dev/sbp/c#t#) - Thanks to Andrzej Krzysztofowicz - -- allow symlink traversal when mounting the root filesystem - -- Create entries for MD devices at MD init - Thanks to Christophe Leroy -=============================================================================== -Changes for patch v21 - -- ported to kernel 2.1.91 -=============================================================================== -Changes for patch v22 - -- SCSI host number patch ("scsihosts=" kernel option) - Thanks to Andrzej Krzysztofowicz -=============================================================================== -Changes for patch v23 - -- Fixed persistence bug with device numbers for manually created - device files - -- Fixed problem with recreating symlinks with different content - -- Added CONFIG_DEVFS_MOUNT (mount devfs on /dev at boot time) -=============================================================================== -Changes for patch v24 - -- Switched from CONFIG_KERNELD to CONFIG_KMOD: module autoloading - should now work again - -- Hide entries which are manually unlinked - -- Always invalidate devfs dentry cache when registering entries - -- Support removal of devfs directories via rmdir(2) - -- Ensure directories created by are visible - -- Default no access for "other" for floppy device -=============================================================================== -Changes for patch v25 - -- Updates to CREDITS file and minor IDE numbering change - Thanks to Andrzej Krzysztofowicz - -- Invalidate devfs dentry cache when making directories - -- Invalidate devfs dentry cache when removing entries - -- More informative message if root FS mount fails when devfs - configured - -- Fixed persistence bug with fifos -=============================================================================== -Changes for patch v26 - -- ported to kernel 2.1.97 - -- Changed serial directory from "/dev/serial" to "/dev/tts" and - "/dev/consoles" to "/dev/vc" to be more friendly to new procps -=============================================================================== -Changes for patch v27 - -- Added support for IDE4 and IDE5 - Thanks to Andrzej Krzysztofowicz - -- Documented "scsihosts=" boot parameter - -- Print process command when debugging kerneld/kmod - -- Added debugging for register/unregister/change operations - -- Added "devfs=" boot options - -- Hide unregistered entries by default -=============================================================================== -Changes for patch v28 - -- No longer lock/unlock superblock in (cope with - recent VFS interface change) - -- Do not automatically change ownership/protection of /dev/tty - -- Drop negative dentries when they are released - -- Manage dcache more efficiently -=============================================================================== -Changes for patch v29 - -- Added DEVFS_FL_AUTO_DEVNUM flag -=============================================================================== -Changes for patch v30 - -- No longer set unnecessary methods - -- Ported to kernel 2.1.99-pre3 -=============================================================================== -Changes for patch v31 - -- Added PID display to debugging message - -- Added "diread" and "diwrite" options - -- Ported to kernel 2.1.102 - -- Fixed persistence problem with permissions -=============================================================================== -Changes for patch v32 - -- Fixed devfs support in drivers/block/md.c -=============================================================================== -Changes for patch v33 - -- Support legacy device nodes - -- Fixed bug where recreated inodes were hidden - -- New IDE naming scheme: everything is under /dev/ide -=============================================================================== -Changes for patch v34 - -- Improved debugging in - -- Prevent duplicate calls to in SCSI layer - -- No longer free old dentries in - -- Free all dentries for a given entry when deleting inodes -=============================================================================== -Changes for patch v35 - -- Ported to kernel 2.1.105 (sound driver changes) -=============================================================================== -Changes for patch v36 - -- Fixed sound driver port -=============================================================================== -Changes for patch v37 - -- Minor documentation tweaks -=============================================================================== -Changes for patch v38 - -- More documentation tweaks - -- Fix for sound driver port - -- Removed ttyname-patch (grab libc 5.4.44 instead) - -- Ported to kernel 2.1.107-pre2 (loop driver fix) -=============================================================================== -Changes for patch v39 - -- Ported to kernel 2.1.107 (hd.c hunk broke due to spelling "fixes"). Sigh - -- Removed many #ifdef's, replaced with trickery in include/devfs_fs.h -=============================================================================== -Changes for patch v40 - -- Fix for sound driver port - -- Limit auto-device numbering to majors 128 to 239 -=============================================================================== -Changes for patch v41 - -- Fixed inode times persistence problem -=============================================================================== -Changes for patch v42 - -- Ported to kernel 2.1.108 (drivers/scsi/hosts.c hunk broke) -=============================================================================== -Changes for patch v43 - -- Fixed spelling in debug - -- Fixed bug in parsing "dilookup" - -- More #ifdef's removed - -- Supported Sparc keyboard (/dev/kbd) - -- Supported DSP56001 digital signal processor (/dev/dsp56k) - -- Supported Apple Desktop Bus (/dev/adb) - -- Supported Coda network file system (/dev/cfs*) -=============================================================================== -Changes for patch v44 - -- Fixed devfs inode leak when manually recreating inodes - -- Fixed permission persistence problem when recreating inodes -=============================================================================== -Changes for patch v45 - -- Ported to kernel 2.1.110 -=============================================================================== -Changes for patch v46 - -- Ported to kernel 2.1.112-pre1 - -- Removed harmless "unused variable" compiler warning - -- Fixed modes for manually recreated device nodes -=============================================================================== -Changes for patch v47 - -- Added NULL devfs inode warning in - -- Force all inode nlink values to 1 -=============================================================================== -Changes for patch v48 - -- Added "dimknod" option - -- Set inode nlink to 0 when freeing dentries - -- Added support for virtual console capture devices (/dev/vcs*) - Thanks to Dennis Hou - -- Fixed modes for manually recreated symlinks -=============================================================================== -Changes for patch v49 - -- Ported to kernel 2.1.113 -=============================================================================== -Changes for patch v50 - -- Fixed bugs in recreated directories and symlinks -=============================================================================== -Changes for patch v51 - -- Improved robustness of rc.devfs script - Thanks to Roderich Schupp - -- Fixed bugs in recreated device nodes - -- Fixed bug in currently unused - -- Defined new type - -- Improved debugging when getting entries - -- Fixed bug where directories could be emptied - -- Ported to kernel 2.1.115 -=============================================================================== -Changes for patch v52 - -- Replaced dummy .epoch inode with .devfsd character device - -- Modified rc.devfs to take account of above change - -- Removed spurious driver warning messages when CONFIG_DEVFS_FS=n - -- Implemented devfsd protocol revision 0 -=============================================================================== -Changes for patch v53 - -- Ported to kernel 2.1.116 (kmod change broke hunk) - -- Updated Documentation/Configure.help - -- Test and tty pattern patch for rc.devfs script - Thanks to Roderich Schupp - -- Added soothing message to warning in -=============================================================================== -Changes for patch v54 - -- Ported to kernel 2.1.117 - -- Fixed default permissions in sound driver - -- Added support for frame buffer devices (/dev/fb*) -=============================================================================== -Changes for patch v55 - -- Ported to kernel 2.1.119 - -- Use GCC extensions for structure initialisations - -- Implemented async open notification - -- Incremented devfsd protocol revision to 1 -=============================================================================== -Changes for patch v56 - -- Ported to kernel 2.1.120-pre3 - -- Moved async open notification to end of -=============================================================================== -Changes for patch v57 - -- Ported to kernel 2.1.121 - -- Prepended "/dev/" to module load request - -- Renamed to - -- Created sample modules.conf file -=============================================================================== -Changes for patch v58 - -- Fixed typo "AYSNC" -> "ASYNC" -=============================================================================== -Changes for patch v59 - -- Added open flag for files -=============================================================================== -Changes for patch v60 - -- Ported to kernel 2.1.123-pre2 -=============================================================================== -Changes for patch v61 - -- Set i_blocks=0 and i_blksize=1024 in -=============================================================================== -Changes for patch v62 - -- Ported to kernel 2.1.123 -=============================================================================== -Changes for patch v63 - -- Ported to kernel 2.1.124-pre2 -=============================================================================== -Changes for patch v64 - -- Fixed Unix98 pty support - -- Increased buffer size in to avoid crash and - burn -=============================================================================== -Changes for patch v65 - -- More Unix98 pty support fixes - -- Added test for empty <> in - -- Renamed to and published - -- Created /dev/root symlink - Thanks to Roderich Schupp - with further modifications by me -=============================================================================== -Changes for patch v66 - -- Yet more Unix98 pty support fixes (now tested) - -- Created - -- Support media change checks when CONFIG_DEVFS_ONLY=y - -- Abolished Unix98-style PTY names for old PTY devices -=============================================================================== -Changes for patch v67 - -- Added inline declaration for dummy - -- Removed spurious "unable to register... in devfs" messages when - CONFIG_DEVFS_FS=n - -- Fixed misc. devices when CONFIG_DEVFS_FS=n - -- Limit auto-device numbering to majors 144 to 239 -=============================================================================== -Changes for patch v68 - -- Hide unopened virtual consoles from directory listings - -- Added support for video capture devices - -- Ported to kernel 2.1.125 -=============================================================================== -Changes for patch v69 - -- Fix for CONFIG_VT=n -=============================================================================== -Changes for patch v70 - -- Added support for non-OSS/Free sound cards -=============================================================================== -Changes for patch v71 - -- Ported to kernel 2.1.126-pre2 -=============================================================================== -Changes for patch v72 - -- #ifdef's for CONFIG_DEVFS_DISABLE_OLD_NAMES removed -=============================================================================== -Changes for patch v73 - -- CONFIG_DEVFS_DISABLE_OLD_NAMES replaced with "nocompat" boot option - -- CONFIG_DEVFS_BOOT_OPTIONS removed: boot options always available -=============================================================================== -Changes for patch v74 - -- Removed CONFIG_DEVFS_MOUNT and "mount" boot option and replaced with - "nomount" boot option - -- Documentation updates - -- Updated sample modules.conf -=============================================================================== -Changes for patch v75 - -- Updated sample modules.conf - -- Remount devfs after initrd finishes - -- Ported to kernel 2.1.127 - -- Added support for ISDN - Thanks to Christophe Leroy -=============================================================================== -Changes for patch v76 - -- Updated an email address in ChangeLog - -- CONFIG_DEVFS_ONLY replaced with "only" boot option -=============================================================================== -Changes for patch v77 - -- Added DEVFS_FL_REMOVABLE flag - -- Check for disc change when listing directories with removable media - devices - -- Use DEVFS_FL_REMOVABLE in sd.c - -- Ported to kernel 2.1.128 -=============================================================================== -Changes for patch v78 - -- Only call on first call to - -- Ported to kernel 2.1.129-pre5 - -- ISDN support improvements - Thanks to Christophe Leroy -=============================================================================== -Changes for patch v79 - -- Ported to kernel 2.1.130 - -- Renamed miscdevice "apm" to "apm_bios" to be consistent with - devices.txt -=============================================================================== -Changes for patch v80 - -- Ported to kernel 2.1.131 - -- Updated for VFS change in 2.1.131 -=============================================================================== -Changes for patch v81 - -- Fixed permissions on /dev/ptmx -=============================================================================== -Changes for patch v82 - -- Ported to kernel 2.1.132-pre4 - -- Changed initial permissions on /dev/pts/* - -- Created - -- Added "symlinks" boot option - -- Changed devfs_register_blkdev() back to register_blkdev() for IDE - -- Check for partitions on removable media in -=============================================================================== -Changes for patch v83 - -- Fixed support for ramdisc when using string-based root FS name - -- Ported to kernel 2.2.0-pre1 -=============================================================================== -Changes for patch v84 - -- Ported to kernel 2.2.0-pre7 -=============================================================================== -Changes for patch v85 - -- Compile fixes for driver/sound/sound_common.c (non-module) and - drivers/isdn/isdn_common.c - Thanks to Christophe Leroy - -- Added support for registering regular files - -- Created - -- Added /dev/cpu/mtrr as an alternative interface to /proc/mtrr - -- Update devfs inodes from entries if not changed through FS -=============================================================================== -Changes for patch v86 - -- Ported to kernel 2.2.0-pre9 -=============================================================================== -Changes for patch v87 - -- Fixed bug when mounting non-devfs devices in a devfs -=============================================================================== -Changes for patch v88 - -- Fixed to only initialise temporary inodes - -- Trap for NULL fops in - -- Return -ENODEV in for non-driver inodes - -- Fixed bug when unswapping non-devfs devices in a devfs -=============================================================================== -Changes for patch v89 - -- Switched to C data types in include/linux/devfs_fs.h - -- Switched from PATH_MAX to DEVFS_PATHLEN - -- Updated Documentation/filesystems/devfs/modules.conf to take account - of reverse scanning (!) by modprobe - -- Ported to kernel 2.2.0 -=============================================================================== -Changes for patch v90 - -- CONFIG_DEVFS_DISABLE_OLD_TTY_NAMES replaced with "nottycompat" boot - option - -- CONFIG_DEVFS_TTY_COMPAT removed: existing "symlinks" boot option now - controls this. This means you must have libc 5.4.44 or later, or a - recent version of libc 6 if you use the "symlinks" option -=============================================================================== -Changes for patch v91 - -- Switch from to in - drivers/char/vc_screen.c to fix problems with Midnight Commander -=============================================================================== -Changes for patch v92 - -- Ported to kernel 2.2.2-pre5 -=============================================================================== -Changes for patch v93 - -- Modified in drivers/scsi/sd.c to cope with devices that - don't exist (which happens with new RAID autostart code printk()s) -=============================================================================== -Changes for patch v94 - -- Fixed bug in joystick driver: only first joystick was registered -=============================================================================== -Changes for patch v95 - -- Fixed another bug in joystick driver - -- Fixed to not overrun event buffer -=============================================================================== -Changes for patch v96 - -- Ported to kernel 2.2.5-2 - -- Created - -- Fixed bugs: compatibility entries were not unregistered for: - loop driver - floppy driver - RAMDISC driver - IDE tape driver - SCSI CD-ROM driver - SCSI HDD driver -=============================================================================== -Changes for patch v97 - -- Fixed bugs: compatibility entries were not unregistered for: - ALSA sound driver - partitions in generic disc driver - -- Don't return unregistred entries in - -- Panic in if entry unregistered - -- Don't panic in for duplicates -=============================================================================== -Changes for patch v98 - -- Don't unregister already unregistered entries in - -- Register entry in - -- Unregister entry in - -- Changed to in drivers/char/tty_io.c - -- Ported to kernel 2.2.7 -=============================================================================== -Changes for patch v99 - -- Ported to kernel 2.2.8 - -- Fixed bug in drivers/scsi/sd.c when >16 SCSI discs - -- Disable warning messages when unable to read partition table for - removable media -=============================================================================== -Changes for patch v100 - -- Ported to kernel 2.3.1-pre5 - -- Added "oops-on-panic" boot option - -- Improved debugging in and - -- Register entry in - -- Unregister entry in - -- Register entry in - -- Unregister entry in - -- Added support for ALSA drivers -=============================================================================== -Changes for patch v101 - -- Ported to kernel 2.3.2 -=============================================================================== -Changes for patch v102 - -- Update serial driver to register PCMCIA entries - Thanks to Roch-Alexandre Nomine-Beguin - -- Updated an email address in ChangeLog - -- Hide virtual console capture entries from directory listings when - corresponding console device is not open -=============================================================================== -Changes for patch v103 - -- Ported to kernel 2.3.3 -=============================================================================== -Changes for patch v104 - -- Added documentation for some functions - -- Added "doc" target to fs/devfs/Makefile - -- Added "v4l" directory for video4linux devices - -- Replaced call to in with call to - - -- Moved registration for sr and sg drivers from detect() to attach() - methods - -- Register entries in and unregister in - -- Work around IDE driver treating CD-ROM as gendisk - -- Use instead of in rc.devfs - -- Updated ToDo list - -- Removed "oops-on-panic" boot option: now always Oops -=============================================================================== -Changes for patch v105 - -- Unregister SCSI host from in - Thanks to Zoltán Böszörményi - -- Don't save /dev/log in rc.devfs - -- Ported to kernel 2.3.4-pre1 -=============================================================================== -Changes for patch v106 - -- Fixed silly typo in drivers/scsi/st.c - -- Improved debugging in -=============================================================================== -Changes for patch v107 - -- Added "diunlink" and "nokmod" boot options - -- Removed superfluous warning message in -=============================================================================== -Changes for patch v108 - -- Remove entries when unloading sound module -=============================================================================== -Changes for patch v109 - -- Ported to kernel 2.3.6-pre2 -=============================================================================== -Changes for patch v110 - -- Took account of change to -=============================================================================== -Changes for patch v111 - -- Created separate event queue for each mounted devfs - -- Removed - -- Created new ioctl()s for devfsd - -- Incremented devfsd protocol revision to 3 - -- Fixed bug when re-creating directories: contents were lost - -- Block access to inodes until devfsd updates permissions -=============================================================================== -Changes for patch v112 - -- Modified patch so it applies against 2.3.5 and 2.3.6 - -- Updated an email address in ChangeLog - -- Do not automatically change ownership/protection of /dev/tty - -- Updated sample modules.conf - -- Switched to sending process uid/gid to devfsd - -- Renamed to - -- Added DEVFSD_NOTIFY_LOOKUP event - -- Added DEVFSD_NOTIFY_CHANGE event - -- Added DEVFSD_NOTIFY_CREATE event - -- Incremented devfsd protocol revision to 4 - -- Moved kernel-specific stuff to include/linux/devfs_fs_kernel.h -=============================================================================== -Changes for patch v113 - -- Ported to kernel 2.3.9 - -- Restricted permissions on some block devices -=============================================================================== -Changes for patch v114 - -- Added support for /dev/netlink - Thanks to Dennis Hou - -- Return EISDIR rather than EINVAL for read(2) on directories - -- Ported to kernel 2.3.10 -=============================================================================== -Changes for patch v115 - -- Added support for all remaining character devices - Thanks to Dennis Hou - -- Cleaned up netlink support -=============================================================================== -Changes for patch v116 - -- Added support for /dev/parport%d - Thanks to Tim Waugh - -- Fixed parallel port ATAPI tape driver - -- Fixed Atari SLM laser printer driver -=============================================================================== -Changes for patch v117 - -- Added support for COSA card - Thanks to Dennis Hou - -- Fixed drivers/char/ppdev.c: missing #include - -- Fixed drivers/char/ftape/zftape/zftape-init.c - Thanks to Vladimir Popov -=============================================================================== -Changes for patch v118 - -- Ported to kernel 2.3.15-pre3 - -- Fixed bug in loop driver - -- Unregister /dev/lp%d entries in drivers/char/lp.c - Thanks to Maciej W. Rozycki -=============================================================================== -Changes for patch v119 - -- Ported to kernel 2.3.16 -=============================================================================== -Changes for patch v120 - -- Fixed bug in drivers/scsi/scsi.c - -- Added /dev/ppp - Thanks to Dennis Hou - -- Ported to kernel 2.3.17 -=============================================================================== -Changes for patch v121 - -- Fixed bug in drivers/block/loop.c - -- Ported to kernel 2.3.18 -=============================================================================== -Changes for patch v122 - -- Ported to kernel 2.3.19 -=============================================================================== -Changes for patch v123 - -- Ported to kernel 2.3.20 -=============================================================================== -Changes for patch v124 - -- Ported to kernel 2.3.21 -=============================================================================== -Changes for patch v125 - -- Created , , - and - Added <> parameter to , , - and - Work sponsored by SGI - -- Fixed apparent bug in COSA driver - -- Re-instated "scsihosts=" boot option -=============================================================================== -Changes for patch v126 - -- Always create /dev/pts if CONFIG_UNIX98_PTYS=y - -- Fixed call to in drivers/block/ide-disk.c - Thanks to Dennis Hou - -- Allow multiple unregistrations - -- Created /dev/scsi hierarchy - Work sponsored by SGI -=============================================================================== -Changes for patch v127 - -Work sponsored by SGI - -- No longer disable devpts if devfs enabled (caveat emptor) - -- Added flags array to struct gendisk and removed code from - drivers/scsi/sd.c - -- Created /dev/discs hierarchy -=============================================================================== -Changes for patch v128 - -Work sponsored by SGI - -- Created /dev/cdroms hierarchy -=============================================================================== -Changes for patch v129 - -Work sponsored by SGI - -- Removed compatibility entries for sound devices - -- Removed compatibility entries for printer devices - -- Removed compatibility entries for video4linux devices - -- Removed compatibility entries for parallel port devices - -- Removed compatibility entries for frame buffer devices -=============================================================================== -Changes for patch v130 - -Work sponsored by SGI - -- Added major and minor number to devfsd protocol - -- Incremented devfsd protocol revision to 5 - -- Removed compatibility entries for SoundBlaster CD-ROMs - -- Removed compatibility entries for netlink devices - -- Removed compatibility entries for SCSI generic devices - -- Removed compatibility entries for SCSI tape devices -=============================================================================== -Changes for patch v131 - -Work sponsored by SGI - -- Support info pointer for all devfs entry types - -- Added <> parameter to and - -- Removed /dev/st hierarchy - -- Removed /dev/sg hierarchy - -- Removed compatibility entries for loop devices - -- Removed compatibility entries for IDE tape devices - -- Removed compatibility entries for SCSI CD-ROMs - -- Removed /dev/sr hierarchy -=============================================================================== -Changes for patch v132 - -Work sponsored by SGI - -- Removed compatibility entries for floppy devices - -- Removed compatibility entries for RAMDISCs - -- Removed compatibility entries for meta-devices - -- Removed compatibility entries for SCSI discs - -- Created - -- Removed /dev/sd hierarchy - -- Support "../" when searching devfs namespace - -- Created /dev/ide/host* hierarchy - -- Supported IDE hard discs in /dev/ide/host* hierarchy - -- Removed compatibility entries for IDE discs - -- Removed /dev/ide/hd hierarchy - -- Supported IDE CD-ROMs in /dev/ide/host* hierarchy - -- Removed compatibility entries for IDE CD-ROMs - -- Removed /dev/ide/cd hierarchy -=============================================================================== -Changes for patch v133 - -Work sponsored by SGI - -- Created - -- Fixed bug in fs/partitions/check.c when rescanning -=============================================================================== -Changes for patch v134 - -Work sponsored by SGI - -- Removed /dev/sd, /dev/sr, /dev/st and /dev/sg directories - -- Removed /dev/ide/hd directory - -- Exported - -- Created and /dev/tapes hierarchy - -- Removed /dev/ide/mt hierarchy - -- Removed /dev/ide/fd hierarchy - -- Ported to kernel 2.3.25 -=============================================================================== -Changes for patch v135 - -Work sponsored by SGI - -- Removed compatibility entries for virtual console capture devices - -- Removed unused - -- Removed compatibility entries for serial devices - -- Removed compatibility entries for console devices - -- Do not hide entries from devfsd or children - -- Removed DEVFS_FL_TTY_COMPAT flag - -- Removed "nottycompat" boot option - -- Removed -=============================================================================== -Changes for patch v136 - -Work sponsored by SGI - -- Moved BSD pty devices to /dev/pty - -- Added DEVFS_FL_WAIT flag -=============================================================================== -Changes for patch v137 - -Work sponsored by SGI - -- Really fixed bug in fs/partitions/check.c when rescanning - -- Support new "disc" naming scheme in - -- Allow NULL fops in - -- Removed redundant name functions in SCSI disc and IDE drivers -=============================================================================== -Changes for patch v138 - -Work sponsored by SGI - -- Fixed old bugs in drivers/block/paride/pt.c, drivers/char/tpqic02.c, - drivers/net/wan/cosa.c and drivers/scsi/scsi.c - Thanks to Sergey Kubushin - -- Fall back to major table if NULL fops given to -=============================================================================== -Changes for patch v139 - -Work sponsored by SGI - -- Corrected and moved and declarations - from arch/alpha/kernel/osf_sys.c to include/linux/fs.h - -- Removed name function from struct gendisk - -- Updated devfs FAQ -=============================================================================== -Changes for patch v140 - -Work sponsored by SGI - -- Ported to kernel 2.3.27 -=============================================================================== -Changes for patch v141 - -Work sponsored by SGI - -- Bug fix in arch/m68k/atari/joystick.c - -- Moved ISDN and capi devices to /dev/isdn -=============================================================================== -Changes for patch v142 - -Work sponsored by SGI - -- Bug fix in drivers/block/ide-probe.c (patch confusion) -=============================================================================== -Changes for patch v143 - -Work sponsored by SGI - -- Bug fix in drivers/block/blkpg.c:partition_name() -=============================================================================== -Changes for patch v144 - -Work sponsored by SGI - -- Ported to kernel 2.3.29 - -- Removed calls to from cdu31a, cm206, mcd and mcdx - CD-ROM drivers: generic driver handles this now - -- Moved joystick devices to /dev/joysticks -=============================================================================== -Changes for patch v145 - -Work sponsored by SGI - -- Ported to kernel 2.3.30-pre3 - -- Register whole-disc entry even for invalid partition tables - -- Fixed bug in mounting root FS when initrd enabled - -- Fixed device entry leak with IDE CD-ROMs - -- Fixed compile problem with drivers/isdn/isdn_common.c - -- Moved COSA devices to /dev/cosa - -- Support fifos when unregistering - -- Created and used in many drivers - -- Moved Coda devices to /dev/coda - -- Moved parallel port IDE tapes to /dev/pt - -- Moved parallel port IDE generic devices to /dev/pg -=============================================================================== -Changes for patch v146 - -Work sponsored by SGI - -- Removed obsolete DEVFS_FL_COMPAT and DEVFS_FL_TOLERANT flags - -- Fixed compile problem with fs/coda/psdev.c - -- Reinstate change to in - drivers/block/ide-probe.c now that fs/isofs/inode.c is fixed - -- Switched to in drivers/block/floppy.c, - drivers/scsi/sr.c and drivers/block/md.c - -- Moved DAC960 devices to /dev/dac960 -=============================================================================== -Changes for patch v147 - -Work sponsored by SGI - -- Ported to kernel 2.3.32-pre4 -=============================================================================== -Changes for patch v148 - -Work sponsored by SGI - -- Removed kmod support: use devfsd instead - -- Moved miscellaneous character devices to /dev/misc -=============================================================================== -Changes for patch v149 - -Work sponsored by SGI - -- Ensure include/linux/joystick.h is OK for user-space - -- Improved debugging in - -- Ensure dentries created by devfsd will be cleaned up -=============================================================================== -Changes for patch v150 - -Work sponsored by SGI - -- Ported to kernel 2.3.34 -=============================================================================== -Changes for patch v151 - -Work sponsored by SGI - -- Ported to kernel 2.3.35-pre1 - -- Created -=============================================================================== -Changes for patch v152 - -Work sponsored by SGI - -- Updated sample modules.conf - -- Ported to kernel 2.3.36-pre1 -=============================================================================== -Changes for patch v153 - -Work sponsored by SGI - -- Ported to kernel 2.3.42 - -- Removed -=============================================================================== -Changes for patch v154 - -Work sponsored by SGI - -- Took account of device number changes for /dev/fb* -=============================================================================== -Changes for patch v155 - -Work sponsored by SGI - -- Ported to kernel 2.3.43-pre8 - -- Moved /dev/tty0 to /dev/vc/0 - -- Moved sequence number formatting from <_tty_make_name> to drivers -=============================================================================== -Changes for patch v156 - -Work sponsored by SGI - -- Fixed breakage in drivers/scsi/sd.c due to recent SCSI changes -=============================================================================== -Changes for patch v157 - -Work sponsored by SGI - -- Ported to kernel 2.3.45 -=============================================================================== -Changes for patch v158 - -Work sponsored by SGI - -- Ported to kernel 2.3.46-pre2 -=============================================================================== -Changes for patch v159 - -Work sponsored by SGI - -- Fixed drivers/block/md.c - Thanks to Mike Galbraith - -- Documentation fixes - -- Moved device registration from to - Thanks to Tim Waugh -=============================================================================== -Changes for patch v160 - -Work sponsored by SGI - -- Fixed drivers/char/joystick/joystick.c - Thanks to Vojtech Pavlik - -- Documentation updates - -- Fixed arch/i386/kernel/mtrr.c if procfs and devfs not enabled - -- Fixed drivers/char/stallion.c -=============================================================================== -Changes for patch v161 - -Work sponsored by SGI - -- Remove /dev/ide when ide-mod is unloaded - -- Fixed bug in drivers/block/ide-probe.c when secondary but no primary - -- Added DEVFS_FL_NO_PERSISTENCE flag - -- Used new DEVFS_FL_NO_PERSISTENCE flag for Unix98 pty slaves - -- Removed unnecessary call to in - - -- Only set auto-ownership for /dev/pty/s* -=============================================================================== -Changes for patch v162 - -Work sponsored by SGI - -- Set inode->i_size to correct size for symlinks - Thanks to Jeremy Fitzhardinge - -- Only give lookup() method to directories to comply with new VFS - assumptions - -- Remove unnecessary tests in symlink methods - -- Don't kill existing block ops in - -- Restore auto-ownership for /dev/pty/m* -=============================================================================== -Changes for patch v163 - -Work sponsored by SGI - -- Don't create missing directories in - -- Removed Documentation/filesystems/devfs/mk-devlinks - -- Updated Documentation/filesystems/devfs/README -=============================================================================== -Changes for patch v164 - -Work sponsored by SGI - -- Fixed CONFIG_DEVFS breakage in drivers/char/serial.c introduced in - linux-2.3.99-pre6-7 -=============================================================================== -Changes for patch v165 - -Work sponsored by SGI - -- Ported to kernel 2.3.99-pre6 -=============================================================================== -Changes for patch v166 - -Work sponsored by SGI - -- Added CONFIG_DEVFS_MOUNT -=============================================================================== -Changes for patch v167 - -Work sponsored by SGI - -- Updated Documentation/filesystems/devfs/README - -- Updated sample modules.conf -=============================================================================== -Changes for patch v168 - -Work sponsored by SGI - -- Disabled multi-mount capability (use VFS bindings instead) - -- Updated README from master HTML file -=============================================================================== -Changes for patch v169 - -Work sponsored by SGI - -- Removed multi-mount code - -- Removed compatibility macros: VFS has changed too much -=============================================================================== -Changes for patch v170 - -Work sponsored by SGI - -- Updated README from master HTML file - -- Merged devfs inode into devfs entry -=============================================================================== -Changes for patch v171 - -Work sponsored by SGI - -- Updated sample modules.conf - -- Removed dead code in which used to call - - -- Ported to kernel 2.4.0-test2-pre3 -=============================================================================== -Changes for patch v172 - -Work sponsored by SGI - -- Changed interface to - -- Changed interface to -=============================================================================== -Changes for patch v173 - -Work sponsored by SGI - -- Simplified interface to - -- Simplified interface to - -- Simplified interface to -=============================================================================== -Changes for patch v174 - -Work sponsored by SGI - -- Updated README from master HTML file -=============================================================================== -Changes for patch v175 - -Work sponsored by SGI - -- DocBook update for fs/devfs/base.c - Thanks to Tim Waugh - -- Removed stale fs/tunnel.c (was never used or completed) -=============================================================================== -Changes for patch v176 - -Work sponsored by SGI - -- Updated ToDo list - -- Removed sample modules.conf: now distributed with devfsd - -- Updated README from master HTML file - -- Ported to kernel 2.4.0-test3-pre4 (which had devfs-patch-v174) -=============================================================================== -Changes for patch v177 - -- Updated README from master HTML file - -- Documentation cleanups - -- Ensure terminates string for root entry - Thanks to Tim Jansen - -- Exported to modules - -- Make send events to devfsd - -- Cleaned up option processing in - -- Fixed bugs in handling symlinks: could leak or cause Oops - -- Cleaned up directory handling by separating fops - Thanks to Alexander Viro -=============================================================================== -Changes for patch v178 - -- Fixed handling of inverted options in -=============================================================================== -Changes for patch v179 - -- Adjusted to account for fix -=============================================================================== -Changes for patch v180 - -- Fixed !CONFIG_DEVFS_FS stub declaration of -=============================================================================== -Changes for patch v181 - -- Answered question posed by Al Viro and removed his comments from - -- Moved setting of registered flag after other fields are changed - -- Fixed race between and - -- Global VFS changes added bogus BKL to devfsd_close(): removed - -- Widened locking in and - -- Replaced stack usage with kmalloc - -- Simplified locking in and fixed memory leak -=============================================================================== -Changes for patch v182 - -- Created and - -- Removed broken devnum allocation and use - -- Fixed old devnum leak by calling new - -- Created - -- Fixed number leak for /dev/cdroms/cdrom%d - -- Fixed number leak for /dev/discs/disc%d -=============================================================================== -Changes for patch v183 - -- Fixed bug in which could hang boot process -=============================================================================== -Changes for patch v184 - -- Documentation typo fix for fs/devfs/util.c - -- Fixed drivers/char/stallion.c for devfs - -- Added DEVFSD_NOTIFY_DELETE event - -- Updated README from master HTML file - -- Removed #include from fs/devfs/base.c -=============================================================================== -Changes for patch v185 - -- Made and in fs/devfs/util.c - private - -- Fixed inode table races by removing it and using inode->u.generic_ip - instead - -- Moved into - -- Moved into -=============================================================================== -Changes for patch v186 - -- Fixed race in for uni-processor - -- Updated README from master HTML file -=============================================================================== -Changes for patch v187 - -- Fixed drivers/char/stallion.c for devfs - -- Fixed drivers/char/rocket.c for devfs - -- Fixed bug in : limited to 128 numbers -=============================================================================== -Changes for patch v188 - -- Updated major masks in fs/devfs/util.c up to Linus' "no new majors" - proclamation. Block: were 126 now 122 free, char: were 26 now 19 free - -- Updated README from master HTML file - -- Removed remnant of multi-mount support in - -- Removed unused DEVFS_FL_SHOW_UNREG flag -=============================================================================== -Changes for patch v189 - -- Removed nlink field from struct devfs_inode - -- Removed auto-ownership for /dev/pty/* (BSD ptys) and used - DEVFS_FL_CURRENT_OWNER|DEVFS_FL_NO_PERSISTENCE for /dev/pty/s* (just - like Unix98 pty slaves) and made /dev/pty/m* rw-rw-rw- access -=============================================================================== -Changes for patch v190 - -- Updated README from master HTML file - -- Replaced BKL with global rwsem to protect symlink data (quick and - dirty hack) -=============================================================================== -Changes for patch v191 - -- Replaced global rwsem for symlink with per-link refcount -=============================================================================== -Changes for patch v192 - -- Removed unnecessary #ifdef CONFIG_DEVFS_FS from arch/i386/kernel/mtrr.c - -- Ported to kernel 2.4.10-pre11 - -- Set inode->i_mapping->a_ops for block nodes in -=============================================================================== -Changes for patch v193 - -- Went back to global rwsem for symlinks (refcount scheme no good) -=============================================================================== -Changes for patch v194 - -- Fixed overrun in by removing function (not needed) - -- Updated README from master HTML file -=============================================================================== -Changes for patch v195 - -- Fixed buffer underrun in - -- Moved down_read() from to -=============================================================================== -Changes for patch v196 - -- Fixed race in when setting event mask - Thanks to Kari Hurtta - -- Avoid deadlock in by using temporary buffer -=============================================================================== -Changes for patch v197 - -- First release of new locking code for devfs core (v1.0) - -- Fixed bug in drivers/cdrom/cdrom.c -=============================================================================== -Changes for patch v198 - -- Discard temporary buffer, now use "%s" for dentry names - -- Don't generate path in : use fake entry instead - -- Use "existing" directory in <_devfs_make_parent_for_leaf> - -- Use slab cache rather than fixed buffer for devfsd events -=============================================================================== -Changes for patch v199 - -- Removed obsolete usage of DEVFS_FL_NO_PERSISTENCE - -- Send DEVFSD_NOTIFY_REGISTERED events in - -- Fixed locking bug in due to typo - -- Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from devfsd - or children -=============================================================================== -Changes for patch v200 - -- Ported to kernel 2.5.1-pre2 -=============================================================================== -Changes for patch v201 - -- Fixed bug in : was dereferencing freed pointer -=============================================================================== -Changes for patch v202 - -- Fixed bug in : was dereferencing freed pointer - -- Added process group check for devfsd privileges -=============================================================================== -Changes for patch v203 - -- Use SLAB_ATOMIC in from -=============================================================================== -Changes for patch v204 - -- Removed long obsolete rc.devfs - -- Return old entry in for 2.4.x kernels - -- Updated README from master HTML file - -- Increment refcount on module in - -- Created and exported - -- Increment refcount on module in - -- Created and used where needed to fix races - -- Added clarifying comments in response to preliminary EMC code review - -- Added poisoning to - -- Improved debugging messages - -- Fixed unregister bugs in drivers/md/lvm-fs.c -=============================================================================== -Changes for patch v205 - -- Corrected (made useful) debugging message in - -- Moved in to - -- Fixed drivers/md/lvm-fs.c to create "lvm" entry - -- Added magic number to guard against scribbling drivers - -- Only return old entry in if a directory - -- Defined macros for error and debug messages - -- Updated README from master HTML file -=============================================================================== -Changes for patch v206 - -- Added support for multiple Compaq cpqarray controllers - -- Fixed (rare, old) race in -=============================================================================== -Changes for patch v207 - -- Fixed deadlock bug in - -- Tag VFS deletable in if handle ignored - -- Updated README from master HTML file -=============================================================================== -Changes for patch v208 - -- Added KERN_* to remaining messages - -- Cleaned up declaration of - -- Updated README from master HTML file -=============================================================================== -Changes for patch v209 - -- Updated README from master HTML file - -- Removed silently introduced calls to lock_kernel() and - unlock_kernel() due to recent VFS locking changes. BKL isn't - required in devfs - -- Changed to allow later additions if not yet empty - -- Added calls to in drivers/block/blkpc.c - and - -- Fixed bug in : was clearing beyond - bitfield - -- Fixed bitfield data type for - -- Made major bitfield type and initialiser 64 bit safe -=============================================================================== -Changes for patch v210 - -- Updated fs/devfs/util.c to fix shift warning on 64 bit machines - Thanks to Anton Blanchard - -- Updated README from master HTML file -=============================================================================== -Changes for patch v211 - -- Do not put miscellaneous character devices in /dev/misc if they - specify their own directory (i.e. contain a '/' character) - -- Copied macro for error messages from fs/devfs/base.c to - fs/devfs/util.c and made use of this macro - -- Removed 2.4.x compatibility code from fs/devfs/base.c -=============================================================================== -Changes for patch v212 - -- Added BKL to because drivers still need it -=============================================================================== -Changes for patch v213 - -- Protected and - from changing directory contents -=============================================================================== -Changes for patch v214 - -- Switched to ISO C structure field initialisers - -- Switch to set_current_state() and move before add_wait_queue() - -- Updated README from master HTML file - -- Fixed devfs entry leak in when *readdir fails -=============================================================================== -Changes for patch v215 - -- Created - -- Switched many functions from to - - -- Switched many functions from to -=============================================================================== -Changes for patch v216 - -- Switched arch/ia64/sn/io/hcl.c from to - - -- Removed deprecated -=============================================================================== -Changes for patch v217 - -- Exported and to modules - -- Updated README from master HTML file - -- Fixed module unload race in -=============================================================================== -Changes for patch v218 - -- Removed DEVFS_FL_AUTO_OWNER flag - -- Switched lingering structure field initialiser to ISO C - -- Added locking when setting/clearing flags - -- Documentation fix in fs/devfs/util.c diff --git a/Documentation/filesystems/devfs/README b/Documentation/filesystems/devfs/README deleted file mode 100644 index aabfba24bc2e..000000000000 --- a/Documentation/filesystems/devfs/README +++ /dev/null @@ -1,1959 +0,0 @@ -Devfs (Device File System) FAQ - - -Linux Devfs (Device File System) FAQ -Richard Gooch -20-AUG-2002 - - -Document languages: - - - - - - - ------------------------------------------------------------------------------ - -NOTE: the master copy of this document is available online at: - -http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html -and looks much better than the text version distributed with the -kernel sources. A mirror site is available at: - -http://www.ras.ucalgary.ca/~rgooch/linux/docs/devfs.html - -There is also an optional daemon that may be used with devfs. You can -find out more about it at: - -http://www.atnf.csiro.au/~rgooch/linux/ - -A mailing list is available which you may subscribe to. Send -email -to majordomo@oss.sgi.com with the following line in the -body of the message: -subscribe devfs -To unsubscribe, send the message body: -unsubscribe devfs -instead. The list is archived at - -http://oss.sgi.com/projects/devfs/archive/. - ------------------------------------------------------------------------------ - -Contents - - -What is it? - -Why do it? - -Who else does it? - -How it works - -Operational issues (essential reading) - -Instructions for the impatient -Permissions persistence across reboots -Dealing with drivers without devfs support -All the way with Devfs -Other Issues -Kernel Naming Scheme -Devfsd Naming Scheme -Old Compatibility Names -SCSI Host Probing Issues - - - -Device drivers currently ported - -Allocation of Device Numbers - -Questions and Answers - -Making things work -Alternatives to devfs -What I don't like about devfs -How to report bugs -Strange kernel messages -Compilation problems with devfsd - - -Other resources - -Translations of this document - - ------------------------------------------------------------------------------ - - -What is it? - -Devfs is an alternative to "real" character and block special devices -on your root filesystem. Kernel device drivers can register devices by -name rather than major and minor numbers. These devices will appear in -devfs automatically, with whatever default ownership and -protection the driver specified. A daemon (devfsd) can be used to -override these defaults. Devfs has been in the kernel since 2.3.46. - -NOTE that devfs is entirely optional. If you prefer the old -disc-based device nodes, then simply leave CONFIG_DEVFS_FS=n (the -default). In this case, nothing will change. ALSO NOTE that if you do -enable devfs, the defaults are such that full compatibility is -maintained with the old devices names. - -There are two aspects to devfs: one is the underlying device -namespace, which is a namespace just like any mounted filesystem. The -other aspect is the filesystem code which provides a view of the -device namespace. The reason I make a distinction is because devfs -can be mounted many times, with each mount showing the same device -namespace. Changes made are global to all mounted devfs filesystems. -Also, because the devfs namespace exists without any devfs mounts, you -can easily mount the root filesystem by referring to an entry in the -devfs namespace. - - -The cost of devfs is a small increase in kernel code size and memory -usage. About 7 pages of code (some of that in __init sections) and 72 -bytes for each entry in the namespace. A modest system has only a -couple of hundred device entries, so this costs a few more -pages. Compare this with the suggestion to put /dev on a ramdisc. - -On a typical machine, the cost is under 0.2 percent. On a modest -system with 64 MBytes of RAM, the cost is under 0.1 percent. The -accusations of "bloatware" levelled at devfs are not justified. - ------------------------------------------------------------------------------ - - -Why do it? - -There are several problems that devfs addresses. Some of these -problems are more serious than others (depending on your point of -view), and some can be solved without devfs. However, the totality of -these problems really calls out for devfs. - -The choice is a patchwork of inefficient user space solutions, which -are complex and likely to be fragile, or to use a simple and efficient -devfs which is robust. - -There have been many counter-proposals to devfs, all seeking to -provide some of the benefits without actually implementing devfs. So -far there has been an absence of code and no proposed alternative has -been able to provide all the features that devfs does. Further, -alternative proposals require far more complexity in user-space (and -still deliver less functionality than devfs). Some people have the -mantra of reducing "kernel bloat", but don't consider the effects on -user-space. - -A good solution limits the total complexity of kernel-space and -user-space. - - -Major&minor allocation - -The existing scheme requires the allocation of major and minor device -numbers for each and every device. This means that a central -co-ordinating authority is required to issue these device numbers -(unless you're developing a "private" device driver), in order to -preserve uniqueness. Devfs shifts the burden to a namespace. This may -not seem like a huge benefit, but actually it is. Since driver authors -will naturally choose a device name which reflects the functionality -of the device, there is far less potential for namespace conflict. -Solving this requires a kernel change. - -/dev management - -Because you currently access devices through device nodes, these must -be created by the system administrator. For standard devices you can -usually find a MAKEDEV programme which creates all these (hundreds!) -of nodes. This means that changes in the kernel must be reflected by -changes in the MAKEDEV programme, or else the system administrator -creates device nodes by hand. - -The basic problem is that there are two separate databases of -major and minor numbers. One is in the kernel and one is in /dev (or -in a MAKEDEV programme, if you want to look at it that way). This is -duplication of information, which is not good practice. -Solving this requires a kernel change. - -/dev growth - -A typical /dev has over 1200 nodes! Most of these devices simply don't -exist because the hardware is not available. A huge /dev increases the -time to access devices (I'm just referring to the dentry lookup times -and the time taken to read inodes off disc: the next subsection shows -some more horrors). - -An example of how big /dev can grow is if we consider SCSI devices: - -host 6 bits (say up to 64 hosts on a really big machine) -channel 4 bits (say up to 16 SCSI buses per host) -id 4 bits -lun 3 bits -partition 6 bits -TOTAL 23 bits - - -This requires 8 Mega (1024*1024) inodes if we want to store all -possible device nodes. Even if we scrap everything but id,partition -and assume a single host adapter with a single SCSI bus and only one -logical unit per SCSI target (id), that's still 10 bits or 1024 -inodes. Each VFS inode takes around 256 bytes (kernel 2.1.78), so -that's 256 kBytes of inode storage on disc (assuming real inodes take -a similar amount of space as VFS inodes). This is actually not so bad, -because disc is cheap these days. Embedded systems would care about -256 kBytes of /dev inodes, but you could argue that embedded systems -would have hand-tuned /dev directories. I've had to do just that on my -embedded systems, but I would rather just leave it to devfs. - -Another issue is the time taken to lookup an inode when first -referenced. Not only does this take time in scanning through a list in -memory, but also the seek times to read the inodes off disc. -This could be solved in user-space using a clever programme which -scanned the kernel logs and deleted /dev entries which are not -available and created them when they were available. This programme -would need to be run every time a new module was loaded, which would -slow things down a lot. - -There is an existing programme called scsidev which will automatically -create device nodes for SCSI devices. It can do this by scanning files -in /proc/scsi. Unfortunately, to extend this idea to other device -nodes would require significant modifications to existing drivers (so -they too would provide information in /proc). This is a non-trivial -change (I should know: devfs has had to do something similar). Once -you go to this much effort, you may as well use devfs itself (which -also provides this information). Furthermore, such a system would -likely be implemented in an ad-hoc fashion, as different drivers will -provide their information in different ways. - -Devfs is much cleaner, because it (naturally) has a uniform mechanism -to provide this information: the device nodes themselves! - - -Node to driver file_operations translation - -There is an important difference between the way disc-based character -and block nodes and devfs entries make the connection between an entry -in /dev and the actual device driver. - -With the current 8 bit major and minor numbers the connection between -disc-based c&b nodes and per-major drivers is done through a -fixed-length table of 128 entries. The various filesystem types set -the inode operations for c&b nodes to {chr,blk}dev_inode_operations, -so when a device is opened a few quick levels of indirection bring us -to the driver file_operations. - -For miscellaneous character devices a second step is required: there -is a scan for the driver entry with the same minor number as the file -that was opened, and the appropriate minor open method is called. This -scanning is done *every time* you open a device node. Potentially, you -may be searching through dozens of misc. entries before you find your -open method. While not an enormous performance overhead, this does -seem pointless. - -Linux *must* move beyond the 8 bit major and minor barrier, -somehow. If we simply increase each to 16 bits, then the indexing -scheme used for major driver lookup becomes untenable, because the -major tables (one each for character and block devices) would need to -be 64 k entries long (512 kBytes on x86, 1 MByte for 64 bit -systems). So we would have to use a scheme like that used for -miscellaneous character devices, which means the search time goes up -linearly with the average number of major device drivers on your -system. Not all "devices" are hardware, some are higher-level drivers -like KGI, so you can get more "devices" without adding hardware -You can improve this by creating an ordered (balanced:-) -binary tree, in which case your search time becomes log(N). -Alternatively, you can use hashing to speed up the search. -But why do that search at all if you don't have to? Once again, it -seems pointless. - -Note that devfs doesn't use the major&minor system. For devfs -entries, the connection is done when you lookup the /dev entry. When -devfs_register() is called, an internal table is appended which has -the entry name and the file_operations. If the dentry cache doesn't -have the /dev entry already, this internal table is scanned to get the -file_operations, and an inode is created. If the dentry cache already -has the entry, there is *no lookup time* (other than the dentry scan -itself, but we can't avoid that anyway, and besides Linux dentries -cream other OS's which don't have them:-). Furthermore, the number of -node entries in a devfs is only the number of available device -entries, not the number of *conceivable* entries. Even if you remove -unnecessary entries in a disc-based /dev, the number of conceivable -entries remains the same: you just limit yourself in order to save -space. - -Devfs provides a fast connection between a VFS node and the device -driver, in a scalable way. - -/dev as a system administration tool - -Right now /dev contains a list of conceivable devices, most of which I -don't have. Devfs only shows those devices available on my -system. This means that listing /dev is a handy way of checking what -devices are available. - -Major&minor size - -Existing major and minor numbers are limited to 8 bits each. This is -now a limiting factor for some drivers, particularly the SCSI disc -driver, which consumes a single major number. Only 16 discs are -supported, and each disc may have only 15 partitions. Maybe this isn't -a problem for you, but some of us are building huge Linux systems with -disc arrays. With devfs an arbitrary pointer can be associated with -each device entry, which can be used to give an effective 32 bit -device identifier (i.e. that's like having a 32 bit minor -number). Since this is private to the kernel, there are no C library -compatibility issues which you would have with increasing major and -minor number sizes. See the section on "Allocation of Device Numbers" -for details on maintaining compatibility with userspace. - -Solving this requires a kernel change. - -Since writing this, the kernel has been modified so that the SCSI disc -driver has more major numbers allocated to it and now supports up to -128 discs. Since these major numbers are non-contiguous (a result of -unplanned expansion), the implementation is a little more cumbersome -than originally. - -Just like the changes to IPv4 to fix impending limitations in the -address space, people find ways around the limitations. In the long -run, however, solutions like IPv6 or devfs can't be put off forever. - -Read-only root filesystem - -Having your device nodes on the root filesystem means that you can't -operate properly with a read-only root filesystem. This is because you -want to change ownerships and protections of tty devices. Existing -practice prevents you using a CD-ROM as your root filesystem for a -*real* system. Sure, you can boot off a CD-ROM, but you can't change -tty ownerships, so it's only good for installing. - -Also, you can't use a shared NFS root filesystem for a cluster of -discless Linux machines (having tty ownerships changed on a common -/dev is not good). Nor can you embed your root filesystem in a -ROM-FS. - -You can get around this by creating a RAMDISC at boot time, making -an ext2 filesystem in it, mounting it somewhere and copying the -contents of /dev into it, then unmounting it and mounting it over -/dev. - -A devfs is a cleaner way of solving this. - -Non-Unix root filesystem - -Non-Unix filesystems (such as NTFS) can't be used for a root -filesystem because they variously don't support character and block -special files or symbolic links. You can't have a separate disc-based -or RAMDISC-based filesystem mounted on /dev because you need device -nodes before you can mount these. Devfs can be mounted without any -device nodes. Devlinks won't work because symlinks aren't supported. -An alternative solution is to use initrd to mount a RAMDISC initial -root filesystem (which is populated with a minimal set of device -nodes), and then construct a new /dev in another RAMDISC, and finally -switch to your non-Unix root filesystem. This requires clever boot -scripts and a fragile and conceptually complex boot procedure. - -Devfs solves this in a robust and conceptually simple way. - -PTY security - -Current pseudo-tty (pty) devices are owned by root and read-writable -by everyone. The user of a pty-pair cannot change -ownership/protections without being suid-root. - -This could be solved with a secure user-space daemon which runs as -root and does the actual creation of pty-pairs. Such a daemon would -require modification to *every* programme that wants to use this new -mechanism. It also slows down creation of pty-pairs. - -An alternative is to create a new open_pty() syscall which does much -the same thing as the user-space daemon. Once again, this requires -modifications to pty-handling programmes. - -The devfs solution allows a device driver to "tag" certain device -files so that when an unopened device is opened, the ownerships are -changed to the current euid and egid of the opening process, and the -protections are changed to the default registered by the driver. When -the device is closed ownership is set back to root and protections are -set back to read-write for everybody. No programme need be changed. -The devpts filesystem provides this auto-ownership feature for Unix98 -ptys. It doesn't support old-style pty devices, nor does it have all -the other features of devfs. - -Intelligent device management - -Devfs implements a simple yet powerful protocol for communication with -a device management daemon (devfsd) which runs in user space. It is -possible to send a message (either synchronously or asynchronously) to -devfsd on any event, such as registration/unregistration of device -entries, opening and closing devices, looking up inodes, scanning -directories and more. This has many possibilities. Some of these are -already implemented. See: - - -http://www.atnf.csiro.au/~rgooch/linux/ - -Device entry registration events can be used by devfsd to change -permissions of newly-created device nodes. This is one mechanism to -control device permissions. - -Device entry registration/unregistration events can be used to run -programmes or scripts. This can be used to provide automatic mounting -of filesystems when a new block device media is inserted into the -drive. - -Asynchronous device open and close events can be used to implement -clever permissions management. For example, the default permissions on -/dev/dsp do not allow everybody to read from the device. This is -sensible, as you don't want some remote user recording what you say at -your console. However, the console user is also prevented from -recording. This behaviour is not desirable. With asynchronous device -open and close events, you can have devfsd run a programme or script -when console devices are opened to change the ownerships for *other* -device nodes (such as /dev/dsp). On closure, you can run a different -script to restore permissions. An advantage of this scheme over -modifying the C library tty handling is that this works even if your -programme crashes (how many times have you seen the utmp database with -lingering entries for non-existent logins?). - -Synchronous device open events can be used to perform intelligent -device access protections. Before the device driver open() method is -called, the daemon must first validate the open attempt, by running an -external programme or script. This is far more flexible than access -control lists, as access can be determined on the basis of other -system conditions instead of just the UID and GID. - -Inode lookup events can be used to authenticate module autoload -requests. Instead of using kmod directly, the event is sent to -devfsd which can implement an arbitrary authentication before loading -the module itself. - -Inode lookup events can also be used to construct arbitrary -namespaces, without having to resort to populating devfs with symlinks -to devices that don't exist. - -Speculative Device Scanning - -Consider an application (like cdparanoia) that wants to find all -CD-ROM devices on the system (SCSI, IDE and other types), whether or -not their respective modules are loaded. The application must -speculatively open certain device nodes (such as /dev/sr0 for the SCSI -CD-ROMs) in order to make sure the module is loaded. This requires -that all Linux distributions follow the standard device naming scheme -(last time I looked RedHat did things differently). Devfs solves the -naming problem. - -The same application also wants to see which devices are actually -available on the system. With the existing system it needs to read the -/dev directory and speculatively open each /dev/sr* device to -determine if the device exists or not. With a large /dev this is an -inefficient operation, especially if there are many /dev/sr* nodes. A -solution like scsidev could reduce the number of /dev/sr* entries (but -of course that also requires all that inefficient directory scanning). - -With devfs, the application can open the /dev/sr directory -(which triggers the module autoloading if required), and proceed to -read /dev/sr. Since only the available devices will have -entries, there are no inefficencies in directory scanning or device -openings. - ------------------------------------------------------------------------------ - -Who else does it? - -FreeBSD has a devfs implementation. Solaris and AIX each have a -pseudo-devfs (something akin to scsidev but for all devices, with some -unspecified kernel support). BeOS, Plan9 and QNX also have it. SGI's -IRIX 6.4 and above also have a device filesystem. - -While we shouldn't just automatically do something because others do -it, we should not ignore the work of others either. FreeBSD has a lot -of competent people working on it, so their opinion should not be -blithely ignored. - ------------------------------------------------------------------------------ - - -How it works - -Registering device entries - -For every entry (device node) in a devfs-based /dev a driver must call -devfs_register(). This adds the name of the device entry, the -file_operations structure pointer and a few other things to an -internal table. Device entries may be added and removed at any -time. When a device entry is registered, it automagically appears in -any mounted devfs'. - -Inode lookup - -When a lookup operation on an entry is performed and if there is no -driver information for that entry devfs will attempt to call -devfsd. If still no driver information can be found then a negative -dentry is yielded and the next stage operation will be called by the -VFS (such as create() or mknod() inode methods). If driver information -can be found, an inode is created (if one does not exist already) and -all is well. - -Manually creating device nodes - -The mknod() method allows you to create an ordinary named pipe in the -devfs, or you can create a character or block special inode if one -does not already exist. You may wish to create a character or block -special inode so that you can set permissions and ownership. Later, if -a device driver registers an entry with the same name, the -permissions, ownership and times are retained. This is how you can set -the protections on a device even before the driver is loaded. Once you -create an inode it appears in the directory listing. - -Unregistering device entries - -A device driver calls devfs_unregister() to unregister an entry. - -Chroot() gaols - -2.2.x kernels - -The semantics of inode creation are different when devfs is mounted -with the "explicit" option. Now, when a device entry is registered, it -will not appear until you use mknod() to create the device. It doesn't -matter if you mknod() before or after the device is registered with -devfs_register(). The purpose of this behaviour is to support -chroot(2) gaols, where you want to mount a minimal devfs inside the -gaol. Only the devices you specifically want to be available (through -your mknod() setup) will be accessible. - -2.4.x kernels - -As of kernel 2.3.99, the VFS has had the ability to rebind parts of -the global filesystem namespace into another part of the namespace. -This now works even at the leaf-node level, which means that -individual files and device nodes may be bound into other parts of the -namespace. This is like making links, but better, because it works -across filesystems (unlike hard links) and works through chroot() -gaols (unlike symbolic links). - -Because of these improvements to the VFS, the multi-mount capability -in devfs is no longer needed. The administrator may create a minimal -device tree inside a chroot(2) gaol by using VFS bindings. As this -provides most of the features of the devfs multi-mount capability, I -removed the multi-mount support code (after issuing an RFC). This -yielded code size reductions and simplifications. - -If you want to construct a minimal chroot() gaol, the following -command should suffice: - -mount --bind /dev/null /gaol/dev/null - - -Repeat for other device nodes you want to expose. Simple! - ------------------------------------------------------------------------------ - - -Operational issues - - -Instructions for the impatient - -Nobody likes reading documentation. People just want to get in there -and play. So this section tells you quickly the steps you need to take -to run with devfs mounted over /dev. Skip these steps and you will end -up with a nearly unbootable system. Subsequent sections describe the -issues in more detail, and discuss non-essential configuration -options. - -Devfsd -OK, if you're reading this, I assume you want to play with -devfs. First you should ensure that /usr/src/linux contains a -recent kernel source tree. Then you need to compile devfsd, the device -management daemon, available at - -http://www.atnf.csiro.au/~rgooch/linux/. -Because the kernel has a naming scheme -which is quite different from the old naming scheme, you need to -install devfsd so that software and configuration files that use the -old naming scheme will not break. - -Compile and install devfsd. You will be provided with a default -configuration file /etc/devfsd.conf which will provide -compatibility symlinks for the old naming scheme. Don't change this -config file unless you know what you're doing. Even if you think you -do know what you're doing, don't change it until you've followed all -the steps below and booted a devfs-enabled system and verified that it -works. - -Now edit your main system boot script so that devfsd is started at the -very beginning (before any filesystem -checks). /etc/rc.d/rc.sysinit is often the main boot script -on systems with SysV-style boot scripts. On systems with BSD-style -boot scripts it is often /etc/rc. Also check -/sbin/rc. - -NOTE that the line you put into the boot -script should be exactly: - -/sbin/devfsd /dev - -DO NOT use some special daemon-launching -programme, otherwise the boot script may not wait for devfsd to finish -initialising. - -System Libraries -There may still be some problems because of broken software making -assumptions about device names. In particular, some software does not -handle devices which are symbolic links. If you are running a libc 5 -based system, install libc 5.4.44 (if you have libc 5.4.46, go back to -libc 5.4.44, which is actually correct). If you are running a glibc -based system, make sure you have glibc 2.1.3 or later. - -/etc/securetty -PAM (Pluggable Authentication Modules) is supposed to be a flexible -mechanism for providing better user authentication and access to -services. Unfortunately, it's also fragile, complex and undocumented -(check out RedHat 6.1, and probably other distributions as well). PAM -has problems with symbolic links. Append the following lines to your -/etc/securetty file: - -vc/1 -vc/2 -vc/3 -vc/4 -vc/5 -vc/6 -vc/7 -vc/8 - -This will not weaken security. If you have a version of util-linux -earlier than 2.10.h, please upgrade to 2.10.h or later. If you -absolutely cannot upgrade, then also append the following lines to -your /etc/securetty file: - -1 -2 -3 -4 -5 -6 -7 -8 - -This may potentially weaken security by allowing root logins over the -network (a password is still required, though). However, since there -are problems with dealing with symlinks, I'm suspicious of the level -of security offered in any case. - -XFree86 -While not essential, it's probably a good idea to upgrade to XFree86 -4.0, as patches went in to make it more devfs-friendly. If you don't, -you'll probably need to apply the following patch to -/etc/security/console.perms so that ordinary users can run -startx. Note that not all distributions have this file (e.g. Debian), -so if it's not present, don't worry about it. - ---- /etc/security/console.perms.orig Sat Apr 17 16:26:47 1999 -+++ /etc/security/console.perms Fri Feb 25 23:53:55 2000 -@@ -14,7 +14,7 @@ - # man 5 console.perms - - # file classes -- these are regular expressions --=tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9] -+=tty[0-9][0-9]* vc/[0-9][0-9]* :[0-9]\.[0-9] :[0-9] - - # device classes -- these are shell-style globs - =/dev/fd[0-1]* - -If the patch does not apply, then change the line: - -=tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9] - -with: - -=tty[0-9][0-9]* vc/[0-9][0-9]* :[0-9]\.[0-9] :[0-9] - - -Disable devpts -I've had a report of devpts mounted on /dev/pts not working -correctly. Since devfs will also manage /dev/pts, there is no -need to mount devpts as well. You should either edit your -/etc/fstab so devpts is not mounted, or disable devpts from -your kernel configuration. - -Unsupported drivers -Not all drivers have devfs support. If you depend on one of these -drivers, you will need to create a script or tarfile that you can use -at boot time to create device nodes as appropriate. There is a -section which describes this. Another -section lists the drivers which have -devfs support. - -/dev/mouse - -Many disributions configure /dev/mouse to be the mouse device -for XFree86 and GPM. I actually think this is a bad idea, because it -adds another level of indirection. When looking at a config file, if -you see /dev/mouse you're left wondering which mouse -is being referred to. Hence I recommend putting the actual mouse -device (for example /dev/psaux) into your -/etc/X11/XF86Config file (and similarly for the GPM -configuration file). - -Alternatively, use the same technique used for unsupported drivers -described above. - -The Kernel -Finally, you need to make sure devfs is compiled into your kernel. Set -CONFIG_EXPERIMENTAL=y, CONFIG_DEVFS_FS=y and CONFIG_DEVFS_MOUNT=y by -using favourite configuration tool (i.e. make config or -make xconfig) and then make clean and then recompile your kernel and -modules. At boot, devfs will be mounted onto /dev. - -If you encounter problems booting (for example if you forgot a -configuration step), you can pass devfs=nomount at the kernel -boot command line. This will prevent the kernel from mounting devfs at -boot time onto /dev. - -In general, a kernel built with CONFIG_DEVFS_FS=y but without mounting -devfs onto /dev is completely safe, and requires no -configuration changes. One exception to take note of is when -LABEL= directives are used in /etc/fstab. In this -case you will be unable to boot properly. This is because the -mount(8) programme uses /proc/partitions as part of -the volume label search process, and the device names it finds are not -available, because setting CONFIG_DEVFS_FS=y changes the names in -/proc/partitions, irrespective of whether devfs is mounted. - -Now you've finished all the steps required. You're now ready to boot -your shiny new kernel. Enjoy. - -Changing the configuration - -OK, you've now booted a devfs-enabled system, and everything works. -Now you may feel like changing the configuration (common targets are -/etc/fstab and /etc/devfsd.conf). Since you have a -system that works, if you make any changes and it doesn't work, you -now know that you only have to restore your configuration files to the -default and it will work again. - - -Permissions persistence across reboots - -If you don't use mknod(2) to create a device file, nor use chmod(2) or -chown(2) to change the ownerships/permissions, the inode ctime will -remain at 0 (the epoch, 12 am, 1-JAN-1970, GMT). Anything with a ctime -later than this has had it's ownership/permissions changed. Hence, a -simple script or programme may be used to tar up all changed inodes, -prior to shutdown. Although effective, many consider this approach a -kludge. - -A much better approach is to use devfsd to save and restore -permissions. It may be configured to record changes in permissions and -will save them in a database (in fact a directory tree), and restore -these upon boot. This is an efficient method and results in immediate -saving of current permissions (unlike the tar approach, which saves -permissions at some unspecified future time). - -The default configuration file supplied with devfsd has config entries -which you may uncomment to enable persistence management. - -If you decide to use the tar approach anyway, be aware that tar will -first unlink(2) an inode before creating a new device node. The -unlink(2) has the effect of breaking the connection between a devfs -entry and the device driver. If you use the "devfs=only" boot option, -you lose access to the device driver, requiring you to reload the -module. I consider this a bug in tar (there is no real need to -unlink(2) the inode first). - -Alternatively, you can use devfsd to provide more sophisticated -management of device permissions. You can use devfsd to store -permissions for whole groups of devices with a single configuration -entry, rather than the conventional single entry per device entry. - -Permissions database stored in mounted-over /dev - -If you wish to save and restore your device permissions into the -disc-based /dev while still mounting devfs onto /dev -you may do so. This requires a 2.4.x kernel (in fact, 2.3.99 or -later), which has the VFS binding facility. You need to do the -following to set this up: - - - -make sure the kernel does not mount devfs at boot time - - -make sure you have a correct /dev/console entry in your -root file-system (where your disc-based /dev lives) - -create the /dev-state directory - - -add the following lines near the very beginning of your boot -scripts: - -mount --bind /dev /dev-state -mount -t devfs none /dev -devfsd /dev - - - - -add the following lines to your /etc/devfsd.conf file: - -REGISTER ^pt[sy] IGNORE -CREATE ^pt[sy] IGNORE -CHANGE ^pt[sy] IGNORE -DELETE ^pt[sy] IGNORE -REGISTER .* COPY /dev-state/$devname $devpath -CREATE .* COPY $devpath /dev-state/$devname -CHANGE .* COPY $devpath /dev-state/$devname -DELETE .* CFUNCTION GLOBAL unlink /dev-state/$devname -RESTORE /dev-state - -Note that the sample devfsd.conf file contains these lines, -as well as other sample configurations you may find useful. See the -devfsd distribution - - -reboot. - - - - -Permissions database stored in normal directory - -If you are using an older kernel which doesn't support VFS binding, -then you won't be able to have the permissions database in a -mounted-over /dev. However, you can still use a regular -directory to store the database. The sample /etc/devfsd.conf -file above may still be used. You will need to create the -/dev-state directory prior to installing devfsd. If you have -old permissions in /dev, then just copy (or move) the device -nodes over to the new directory. - -Which method is better? - -The best method is to have the permissions database stored in the -mounted-over /dev. This is because you will not need to copy -device nodes over to /dev-state, and because it allows you to -switch between devfs and non-devfs kernels, without requiring you to -copy permissions between /dev-state (for devfs) and -/dev (for non-devfs). - - -Dealing with drivers without devfs support - -Currently, not all device drivers in the kernel have been modified to -use devfs. Device drivers which do not yet have devfs support will not -automagically appear in devfs. The simplest way to create device nodes -for these drivers is to unpack a tarfile containing the required -device nodes. You can do this in your boot scripts. All your drivers -will now work as before. - -Hopefully for most people devfs will have enough support so that they -can mount devfs directly over /dev without losing most functionality -(i.e. losing access to various devices). As of 22-JAN-1998 (devfs -patch version 10) I am now running this way. All the devices I have -are available in devfs, so I don't lose anything. - -WARNING: if your configuration requires the old-style device names -(i.e. /dev/hda1 or /dev/sda1), you must install devfsd and configure -it to maintain compatibility entries. It is almost certain that you -will require this. Note that the kernel creates a compatibility entry -for the root device, so you don't need initrd. - -Note that you no longer need to mount devpts if you use Unix98 PTYs, -as devfs can manage /dev/pts itself. This saves you some RAM, as you -don't need to compile and install devpts. Note that some versions of -glibc have a bug with Unix98 pty handling on devfs systems. Contact -the glibc maintainers for a fix. Glibc 2.1.3 has the fix. - -Note also that apart from editing /etc/fstab, other things will need -to be changed if you *don't* install devfsd. Some software (like the X -server) hard-wire device names in their source. It really is much -easier to install devfsd so that compatibility entries are created. -You can then slowly migrate your system to using the new device names -(for example, by starting with /etc/fstab), and then limiting the -compatibility entries that devfsd creates. - -IF YOU CONFIGURE TO MOUNT DEVFS AT BOOT, MAKE SURE YOU INSTALL DEVFSD -BEFORE YOU BOOT A DEVFS-ENABLED KERNEL! - -Now that devfs has gone into the 2.3.46 kernel, I'm getting a lot of -reports back. Many of these are because people are trying to run -without devfsd, and hence some things break. Please just run devfsd if -things break. I want to concentrate on real bugs rather than -misconfiguration problems at the moment. If people are willing to fix -bugs/false assumptions in other code (i.e. glibc, X server) and submit -that to the respective maintainers, that would be great. - - -All the way with Devfs - -The devfs kernel patch creates a rationalised device tree. As stated -above, if you want to keep using the old /dev naming scheme, -you just need to configure devfsd appopriately (see the man -page). People who prefer the old names can ignore this section. For -those of us who like the rationalised names and an uncluttered -/dev, read on. - -If you don't run devfsd, or don't enable compatibility entry -management, then you will have to configure your system to use the new -names. For example, you will then need to edit your -/etc/fstab to use the new disc naming scheme. If you want to -be able to boot non-devfs kernels, you will need compatibility -symlinks in the underlying disc-based /dev pointing back to -the old-style names for when you boot a kernel without devfs. - -You can selectively decide which devices you want compatibility -entries for. For example, you may only want compatibility entries for -BSD pseudo-terminal devices (otherwise you'll have to patch you C -library or use Unix98 ptys instead). It's just a matter of putting in -the correct regular expression into /dev/devfsd.conf. - -There are other choices of naming schemes that you may prefer. For -example, I don't use the kernel-supplied -names, because they are too verbose. A common misconception is -that the kernel-supplied names are meant to be used directly in -configuration files. This is not the case. They are designed to -reflect the layout of the devices attached and to provide easy -classification. - -If you like the kernel-supplied names, that's fine. If you don't then -you should be using devfsd to construct a namespace more to your -liking. Devfsd has built-in code to construct a -namespace that is both logical and easy to -manage. In essence, it creates a convenient abbreviation of the -kernel-supplied namespace. - -You are of course free to build your own namespace. Devfsd has all the -infrastructure required to make this easy for you. All you need do is -write a script. You can even write some C code and devfsd can load the -shared object as a callable extension. - - -Other Issues - -The init programme -Another thing to take note of is whether your init programme -creates a Unix socket /dev/telinit. Some versions of init -create /dev/telinit so that the telinit programme can -communicate with the init process. If you have such a system you need -to make sure that devfs is mounted over /dev *before* init -starts. In other words, you can't leave the mounting of devfs to -/etc/rc, since this is executed after init. Other -versions of init require a named pipe /dev/initctl -which must exist *before* init starts. Once again, you need to -mount devfs and then create the named pipe *before* init -starts. - -The default behaviour now is not to mount devfs onto /dev at -boot time for 2.3.x and later kernels. You can correct this with the -"devfs=mount" boot option. This solves any problems with init, -and also prevents the dreaded: - -Cannot open initial console - -message. For 2.2.x kernels where you need to apply the devfs patch, -the default is to mount. - -If you have automatic mounting of devfs onto /dev then you -may need to create /dev/initctl in your boot scripts. The -following lines should suffice: - -mknod /dev/initctl p -kill -SIGUSR1 1 # tell init that /dev/initctl now exists - -Alternatively, if you don't want the kernel to mount devfs onto -/dev then you could use the following procedure is a -guideline for how to get around /dev/initctl problems: - -# cd /sbin -# mv init init.real -# cat > init -#! /bin/sh -mount -n -t devfs none /dev -mknod /dev/initctl p -exec /sbin/init.real $* -[control-D] -# chmod a+x init - -Note that newer versions of init create /dev/initctl -automatically, so you don't have to worry about this. - -Module autoloading -You will need to configure devfsd to enable module -autoloading. The following lines should be placed in your -/etc/devfsd.conf file: - -LOOKUP .* MODLOAD - - -As of devfsd-v1.3.10, a generic /etc/modules.devfs -configuration file is installed, which is used by the MODLOAD -action. This should be sufficient for most configurations. If you -require further configuration, edit your /etc/modules.conf -file. The way module autoloading work with devfs is: - - -a process attempts to lookup a device node (e.g. /dev/fred) - - -if that device node does not exist, the full pathname is passed to -devfsd as a string - - -devfsd will pass the string to the modprobe programme (provided the -configuration line shown above is present), and specifies that -/etc/modules.devfs is the configuration file - - -/etc/modules.devfs includes /etc/modules.conf to -access local configurations - -modprobe will search it's configuration files, looking for an alias -that translates the pathname into a module name - - -the translated pathname is then used to load the module. - - -If you wanted a lookup of /dev/fred to load the -mymod module, you would require the following configuration -line in /etc/modules.conf: - -alias /dev/fred mymod - -The /etc/modules.devfs configuration file provides many such -aliases for standard device names. If you look closely at this file, -you will note that some modules require multiple alias configuration -lines. This is required to support module autoloading for old and new -device names. - -Mounting root off a devfs device -If you wish to mount root off a devfs device when you pass the -"devfs=only" boot option, then you need to pass in the -"root=" option to the kernel when booting. If you use -LILO, then you must have this in lilo.conf: - -append = "root=" - -Surprised? Yep, so was I. It turns out if you have (as most people -do): - -root = - - -then LILO will determine the device number of and will -write that device number into a special place in the kernel image -before starting the kernel, and the kernel will use that device number -to mount the root filesystem. So, using the "append" variety ensures -that LILO passes the root filesystem device as a string, which devfs -can then use. - -Note that this isn't an issue if you don't pass "devfs=only". - -TTY issues -The ttyname(3) function in some versions of the C library makes -false assumptions about device entries which are symbolic links. The -tty(1) programme is one that depends on this function. I've -written a patch to libc 5.4.43 which fixes this. This has been -included in libc 5.4.44 and a similar fix is in glibc 2.1.3. - - -Kernel Naming Scheme - -The kernel provides a default naming scheme. This scheme is designed -to make it easy to search for specific devices or device types, and to -view the available devices. Some device types (such as hard discs), -have a directory of entries, making it easy to see what devices of -that class are available. Often, the entries are symbolic links into a -directory tree that reflects the topology of available devices. The -topological tree is useful for finding how your devices are arranged. - -Below is a list of the naming schemes for the most common drivers. A -list of reserved device names is -available for reference. Please send email to -rgooch@atnf.csiro.au to obtain an allocation. Please be -patient (the maintainer is busy). An alternative name may be allocated -instead of the requested name, at the discretion of the maintainer. - -Disc Devices - -All discs, whether SCSI, IDE or whatever, are placed under the -/dev/discs hierarchy: - - /dev/discs/disc0 first disc - /dev/discs/disc1 second disc - - -Each of these entries is a symbolic link to the directory for that -device. The device directory contains: - - disc for the whole disc - part* for individual partitions - - -CD-ROM Devices - -All CD-ROMs, whether SCSI, IDE or whatever, are placed under the -/dev/cdroms hierarchy: - - /dev/cdroms/cdrom0 first CD-ROM - /dev/cdroms/cdrom1 second CD-ROM - - -Each of these entries is a symbolic link to the real device entry for -that device. - -Tape Devices - -All tapes, whether SCSI, IDE or whatever, are placed under the -/dev/tapes hierarchy: - - /dev/tapes/tape0 first tape - /dev/tapes/tape1 second tape - - -Each of these entries is a symbolic link to the directory for that -device. The device directory contains: - - mt for mode 0 - mtl for mode 1 - mtm for mode 2 - mta for mode 3 - mtn for mode 0, no rewind - mtln for mode 1, no rewind - mtmn for mode 2, no rewind - mtan for mode 3, no rewind - - -SCSI Devices - -To uniquely identify any SCSI device requires the following -information: - - controller (host adapter) - bus (SCSI channel) - target (SCSI ID) - unit (Logical Unit Number) - - -All SCSI devices are placed under /dev/scsi (assuming devfs -is mounted on /dev). Hence, a SCSI device with the following -parameters: c=1,b=2,t=3,u=4 would appear as: - - /dev/scsi/host1/bus2/target3/lun4 device directory - - -Inside this directory, a number of device entries may be created, -depending on which SCSI device-type drivers were installed. - -See the section on the disc naming scheme to see what entries the SCSI -disc driver creates. - -See the section on the tape naming scheme to see what entries the SCSI -tape driver creates. - -The SCSI CD-ROM driver creates: - - cd - - -The SCSI generic driver creates: - - generic - - -IDE Devices - -To uniquely identify any IDE device requires the following -information: - - controller - bus (aka. primary/secondary) - target (aka. master/slave) - unit - - -All IDE devices are placed under /dev/ide, and uses a similar -naming scheme to the SCSI subsystem. - -XT Hard Discs - -All XT discs are placed under /dev/xd. The first XT disc has -the directory /dev/xd/disc0. - -TTY devices - -The tty devices now appear as: - - New name Old-name Device Type - -------- -------- ----------- - /dev/tts/{0,1,...} /dev/ttyS{0,1,...} Serial ports - /dev/cua/{0,1,...} /dev/cua{0,1,...} Call out devices - /dev/vc/0 /dev/tty Current virtual console - /dev/vc/{1,2,...} /dev/tty{1...63} Virtual consoles - /dev/vcc/{0,1,...} /dev/vcs{1...63} Virtual consoles - /dev/pty/m{0,1,...} /dev/ptyp?? PTY masters - /dev/pty/s{0,1,...} /dev/ttyp?? PTY slaves - - -RAMDISCS - -The RAMDISCS are placed in their own directory, and are named thus: - - /dev/rd/{0,1,2,...} - - -Meta Devices - -The meta devices are placed in their own directory, and are named -thus: - - /dev/md/{0,1,2,...} - - -Floppy discs - -Floppy discs are placed in the /dev/floppy directory. - -Loop devices - -Loop devices are placed in the /dev/loop directory. - -Sound devices - -Sound devices are placed in the /dev/sound directory -(audio, sequencer, ...). - - -Devfsd Naming Scheme - -Devfsd provides a naming scheme which is a convenient abbreviation of -the kernel-supplied namespace. In some -cases, the kernel-supplied naming scheme is quite convenient, so -devfsd does not provide another naming scheme. The convenience names -that devfsd creates are in fact the same names as the original devfs -kernel patch created (before Linus mandated the Big Name -Change). These are referred to as "new compatibility entries". - -In order to configure devfsd to create these convenience names, the -following lines should be placed in your /etc/devfsd.conf: - -REGISTER .* MKNEWCOMPAT -UNREGISTER .* RMNEWCOMPAT - -This will cause devfsd to create (and destroy) symbolic links which -point to the kernel-supplied names. - -SCSI Hard Discs - -All SCSI discs are placed under /dev/sd (assuming devfs is -mounted on /dev). Hence, a SCSI disc with the following -parameters: c=1,b=2,t=3,u=4 would appear as: - - /dev/sd/c1b2t3u4 for the whole disc - /dev/sd/c1b2t3u4p5 for the 5th partition - /dev/sd/c1b2t3u4p5s6 for the 6th slice in the 5th partition - - -SCSI Tapes - -All SCSI tapes are placed under /dev/st. A similar naming -scheme is used as for SCSI discs. A SCSI tape with the -parameters:c=1,b=2,t=3,u=4 would appear as: - - /dev/st/c1b2t3u4m0 for mode 0 - /dev/st/c1b2t3u4m1 for mode 1 - /dev/st/c1b2t3u4m2 for mode 2 - /dev/st/c1b2t3u4m3 for mode 3 - /dev/st/c1b2t3u4m0n for mode 0, no rewind - /dev/st/c1b2t3u4m1n for mode 1, no rewind - /dev/st/c1b2t3u4m2n for mode 2, no rewind - /dev/st/c1b2t3u4m3n for mode 3, no rewind - - -SCSI CD-ROMs - -All SCSI CD-ROMs are placed under /dev/sr. A similar naming -scheme is used as for SCSI discs. A SCSI CD-ROM with the -parameters:c=1,b=2,t=3,u=4 would appear as: - - /dev/sr/c1b2t3u4 - - -SCSI Generic Devices - -The generic (aka. raw) interface for all SCSI devices are placed under -/dev/sg. A similar naming scheme is used as for SCSI discs. A -SCSI generic device with the parameters:c=1,b=2,t=3,u=4 would appear -as: - - /dev/sg/c1b2t3u4 - - -IDE Hard Discs - -All IDE discs are placed under /dev/ide/hd, using a similar -convention to SCSI discs. The following mappings exist between the new -and the old names: - - /dev/hda /dev/ide/hd/c0b0t0u0 - /dev/hdb /dev/ide/hd/c0b0t1u0 - /dev/hdc /dev/ide/hd/c0b1t0u0 - /dev/hdd /dev/ide/hd/c0b1t1u0 - - -IDE Tapes - -A similar naming scheme is used as for IDE discs. The entries will -appear in the /dev/ide/mt directory. - -IDE CD-ROM - -A similar naming scheme is used as for IDE discs. The entries will -appear in the /dev/ide/cd directory. - -IDE Floppies - -A similar naming scheme is used as for IDE discs. The entries will -appear in the /dev/ide/fd directory. - -XT Hard Discs - -All XT discs are placed under /dev/xd. The first XT disc -would appear as /dev/xd/c0t0. - - -Old Compatibility Names - -The old compatibility names are the legacy device names, such as -/dev/hda, /dev/sda, /dev/rtc and so on. -Devfsd can be configured to create compatibility symlinks so that you -may continue to use the old names in your configuration files and so -that old applications will continue to function correctly. - -In order to configure devfsd to create these legacy names, the -following lines should be placed in your /etc/devfsd.conf: - -REGISTER .* MKOLDCOMPAT -UNREGISTER .* RMOLDCOMPAT - -This will cause devfsd to create (and destroy) symbolic links which -point to the kernel-supplied names. - - ------------------------------------------------------------------------------ - - -Device drivers currently ported - -- All miscellaneous character devices support devfs (this is done - transparently through misc_register()) - -- SCSI discs and generic hard discs - -- Character memory devices (null, zero, full and so on) - Thanks to C. Scott Ananian - -- Loop devices (/dev/loop?) - -- TTY devices (console, serial ports, terminals and pseudo-terminals) - Thanks to C. Scott Ananian - -- SCSI tapes (/dev/scsi and /dev/tapes) - -- SCSI CD-ROMs (/dev/scsi and /dev/cdroms) - -- SCSI generic devices (/dev/scsi) - -- RAMDISCS (/dev/ram?) - -- Meta Devices (/dev/md*) - -- Floppy discs (/dev/floppy) - -- Parallel port printers (/dev/printers) - -- Sound devices (/dev/sound) - Thanks to Eric Dumas and - C. Scott Ananian - -- Joysticks (/dev/joysticks) - -- Sparc keyboard (/dev/kbd) - -- DSP56001 digital signal processor (/dev/dsp56k) - -- Apple Desktop Bus (/dev/adb) - -- Coda network file system (/dev/cfs*) - -- Virtual console capture devices (/dev/vcc) - Thanks to Dennis Hou - -- Frame buffer devices (/dev/fb) - -- Video capture devices (/dev/v4l) - - ------------------------------------------------------------------------------ - - -Allocation of Device Numbers - -Devfs allows you to write a driver which doesn't need to allocate a -device number (major&minor numbers) for the internal operation of the -kernel. However, there are a number of userspace programmes that use -the device number as a unique handle for a device. An example is the -find programme, which uses device numbers to determine whether -an inode is on a different filesystem than another inode. The device -number used is the one for the block device which a filesystem is -using. To preserve compatibility with userspace programmes, block -devices using devfs need to have unique device numbers allocated to -them. Furthermore, POSIX specifies device numbers, so some kind of -device number needs to be presented to userspace. - -The simplest option (especially when porting drivers to devfs) is to -keep using the old major and minor numbers. Devfs will take whatever -values are given for major&minor and pass them onto userspace. - -This device number is a 16 bit number, so this leaves plenty of space -for large numbers of discs and partitions. This scheme can also be -used for character devices, in particular the tty devices, which are -currently limited to 256 pseudo-ttys (this limits the total number of -simultaneous xterms and remote logins). Note that the device number -is limited to the range 36864-61439 (majors 144-239), in order to -avoid any possible conflicts with existing official allocations. - -Please note that using dynamically allocated block device numbers may -break the NFS daemons (both user and kernel mode), which expect dev_t -for a given device to be constant over the lifetime of remote mounts. - -A final note on this scheme: since it doesn't increase the size of -device numbers, there are no compatibility issues with userspace. - ------------------------------------------------------------------------------ - - -Questions and Answers - - -Making things work -Alternatives to devfs -What I don't like about devfs -How to report bugs -Strange kernel messages -Compilation problems with devfsd - - - -Making things work - -Here are some common questions and answers. - - - -Devfsd doesn't start - -Make sure you have compiled and installed devfsd -Make sure devfsd is being started from your boot -scripts -Make sure you have configured your kernel to enable devfs (see -below) -Make sure devfs is mounted (see below) - - -Devfsd is not managing all my permissions - -Make sure you are capturing the appropriate events. For example, -device entries created by the kernel generate REGISTER events, -but those created by devfsd generate CREATE events. - - -Devfsd is not capturing all REGISTER events - -See the previous entry: you may need to capture CREATE events. - - -X will not start - -Make sure you followed the steps -outlined above. - - -Why don't my network devices appear in devfs? - -This is not a bug. Network devices have their own, completely separate -namespace. They are accessed via socket(2) and -setsockopt(2) calls, and thus require no device nodes. I have -raised the possibilty of moving network devices into the device -namespace, but have had no response. - - -How can I test if I have devfs compiled into my kernel? - -All filesystems built-in or currently loaded are listed in -/proc/filesystems. If you see a devfs entry, then -you know that devfs was compiled into your kernel. If you have -correctly configured and rebuilt your kernel, then devfs will be -built-in. If you think you've configured it in, but -/proc/filesystems doesn't show it, you've made a mistake. -Common mistakes include: - -Using a 2.2.x kernel without applying the devfs patch (if you -don't know how to patch your kernel, use 2.4.x instead, don't bother -asking me how to patch) -Forgetting to set CONFIG_EXPERIMENTAL=y -Forgetting to set CONFIG_DEVFS_FS=y -Forgetting to set CONFIG_DEVFS_MOUNT=y (if you want devfs -to be automatically mounted at boot) -Editing your .config manually, instead of using make -config or make xconfig -Forgetting to run make dep; make clean after changing the -configuration and before compiling -Forgetting to compile your kernel and modules -Forgetting to install your kernel -Forgetting to install your modules - -Please check twice that you've done all these steps before sending in -a bug report. - - - -How can I test if devfs is mounted on /dev? - -The device filesystem will always create an entry called -".devfsd", which is used to communicate with the daemon. Even -if the daemon is not running, this entry will exist. Testing for the -existence of this entry is the approved method of determining if devfs -is mounted or not. Note that the type of entry (i.e. regular file, -character device, named pipe, etc.) may change without notice. Only -the existence of the entry should be relied upon. - - -When I start devfsd, I see the error: -Error opening file: ".devfsd" No such file or directory? - -This means that devfs is not mounted. Make sure you have devfs mounted. - - -How do I mount devfs? - -First make sure you have devfs compiled into your kernel (see -above). Then you will either need to: - -set CONFIG_DEVFS_MOUNT=y in your kernel config -pass devfs=mount to your boot loader -mount devfs manually in your boot scripts with: -mount -t none devfs /dev - - - -Mount by volume LABEL=