From 67594feb4b68074d8807f5566536e06db9130679 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 17 May 2005 13:04:49 -0500 Subject: [CIFS] missing break needed to handle < when mount option "mapchars" specified Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/README | 4 ++-- fs/cifs/misc.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/cifs/README b/fs/cifs/README index e74df0c73256..34b0cf7111f3 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -371,7 +371,7 @@ A partial list of the supported mount options follows: on newly created files, directories, and devices (create, mkdir, mknod) which will result in the server setting the uid and gid to the default (usually the server uid of the - usern who mounted the share). Letting the server (rather than + user who mounted the share). Letting the server (rather than the client) set the uid and gid is the default. This parameter has no effect if the CIFS Unix Extensions are not negotiated. @@ -384,7 +384,7 @@ A partial list of the supported mount options follows: client (e.g. when the application is doing large sequential reads bigger than page size without rereading the same data) this can provide better performance than the default - behavior which caches reads (reaadahead) and writes + behavior which caches reads (readahead) and writes (writebehind) through the local Linux client pagecache if oplock (caching token) is granted and held. Note that direct allows write operations larger than page size diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index db14b503d89e..072b4ee8c53e 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -571,6 +571,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, break; case UNI_LESSTHAN: target[j] = '<'; + break; default: len = cp->uni2char(src_char, &target[j], NLS_MAX_CHARSET_SIZE); -- cgit v1.2.3 From b2aeb9d565be5ef00fb9f921c6d2459c74d90cdf Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 17 May 2005 13:16:18 -0500 Subject: [CIFS] Fix oops in cifs_unlink. Caused in some cases when renaming over existing, newly created, file. Samba bugzilla: 2697 Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/dir.c | 3 ++- fs/cifs/inode.c | 24 +++++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e3137aa48cdd..3f3538d4a1fa 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -392,7 +392,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name rc = 0; d_add(direntry, NULL); } else { - cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc)); + cERROR(1,("Error 0x%x on cifs_get_inode_info in lookup of %s", + rc,full_path)); /* BB special case check for Access Denied - watch security exposure of returning dir info implicitly via different rc if file exists or not but no access BB */ diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 670947288262..b8b78cbb34c9 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -422,7 +422,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { - direntry->d_inode->i_nlink--; + if(direntry->d_inode) + direntry->d_inode->i_nlink--; } else if (rc == -ENOENT) { d_drop(direntry); } else if (rc == -ETXTBSY) { @@ -440,7 +441,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); - direntry->d_inode->i_nlink--; + if(direntry->d_inode) + direntry->d_inode->i_nlink--; } } else if (rc == -EACCES) { /* try only if r/o attribute set in local lookup data? */ @@ -494,7 +496,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { - direntry->d_inode->i_nlink--; + if(direntry->d_inode) + direntry->d_inode->i_nlink--; } else if (rc == -ETXTBSY) { int oplock = FALSE; __u16 netfid; @@ -514,17 +517,20 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); - direntry->d_inode->i_nlink--; + if(direntry->d_inode) + direntry->d_inode->i_nlink--; } /* BB if rc = -ETXTBUSY goto the rename logic BB */ } } } - cifsInode = CIFS_I(direntry->d_inode); - cifsInode->time = 0; /* will force revalidate to get info when - needed */ - direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = - current_fs_time(inode->i_sb); + if(direntry->d_inode) { + cifsInode = CIFS_I(direntry->d_inode); + cifsInode->time = 0; /* will force revalidate to get info + when needed */ + direntry->d_inode->i_ctime = current_fs_time(inode->i_sb); + } + inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); cifsInode = CIFS_I(inode); cifsInode->time = 0; /* force revalidate of dir as well */ -- cgit v1.2.3 From b1a45695bde0204597957e448923f09ce271ca80 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 17 May 2005 16:07:23 -0500 Subject: [CIFS] fix casts of unicode strings to match function definition Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/cifsproto.h | 2 +- fs/cifs/cifssmb.c | 56 ++++++++++++++++++++++++++--------------------------- 2 files changed, 29 insertions(+), 29 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0010511083fc..ea239dea571e 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -228,7 +228,7 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const struct nls_table *nls_codepage, int remap_special_chars); #endif /* CONFIG_CIFS_EXPERIMENTAL */ -extern int cifs_convertUCSpath(char *target, const __u16 *source, int maxlen, +extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, const struct nls_table * codepage); extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen, const struct nls_table * cp, int mapChars); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 741ff0c69f37..3c628bf667a5 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -567,7 +567,7 @@ DelFileRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->fileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -665,7 +665,7 @@ MkDirRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__u16 *) pSMB->DirName, name, + name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -719,7 +719,7 @@ openRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { count = 1; /* account for one byte pad to word boundary */ name_len = - cifsConvertToUCS((__u16 *) (pSMB->fileName + 1), + cifsConvertToUCS((__le16 *) (pSMB->fileName + 1), fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -1141,7 +1141,7 @@ renameRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName, + cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -1149,7 +1149,7 @@ renameRetry: /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; name_len2 = - cifsConvertToUCS((__u16 *) &pSMB->OldFileName[name_len + 2], + cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2], toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ @@ -1236,10 +1236,10 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, /* unicode only call */ if(target_name == NULL) { sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid); - len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name, + len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name, dummy_string, 24, nls_codepage, remap); } else { - len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name, + len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name, target_name, PATH_MAX, nls_codepage, remap); } rename_info->target_name_len = cpu_to_le32(2 * len_of_str); @@ -1296,7 +1296,7 @@ copyRetry: pSMB->Flags = cpu_to_le16(flags & COPY_TREE); if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__u16 *) pSMB->OldFileName, + name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ @@ -1304,7 +1304,7 @@ copyRetry: pSMB->OldFileName[name_len] = 0x04; /* pad */ /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; - name_len2 = cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2], + name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ @@ -1453,7 +1453,7 @@ createHardLinkRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__u16 *) pSMB->FileName, toName, + name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -1476,7 +1476,7 @@ createHardLinkRetry: data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifsConvertToUCS((__u16 *) data_offset, fromName, PATH_MAX, + cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX, nls_codepage, remap); name_len_target++; /* trailing null */ name_len_target *= 2; @@ -1546,14 +1546,14 @@ winCreateHardLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName, + cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0; /* pad */ pSMB->OldFileName[name_len + 1] = 0x04; name_len2 = - cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2], + cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ @@ -1939,7 +1939,7 @@ queryAclRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2024,7 +2024,7 @@ setAclRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2188,7 +2188,7 @@ QPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2269,7 +2269,7 @@ UnixQPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2350,7 +2350,7 @@ findUniqueRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -2435,7 +2435,7 @@ findFirstRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName,searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName,searchName, PATH_MAX, nls_codepage, remap); /* We can not add the asterik earlier in case it got remapped to 0xF03A as if it were part of the @@ -2726,7 +2726,7 @@ GetInodeNumberRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX,nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2837,7 +2837,7 @@ getDFSRetry: if (ses->capabilities & CAP_UNICODE) { pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; name_len = - cifsConvertToUCS((__u16 *) pSMB->RequestFileName, + cifsConvertToUCS((__le16 *) pSMB->RequestFileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -3369,7 +3369,7 @@ SetEOFRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -3627,7 +3627,7 @@ SetTimesRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -3708,7 +3708,7 @@ SetAttrLgcyRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - ConvertToUCS((wchar_t *) pSMB->fileName, fileName, + ConvertToUCS((__le16 *) pSMB->fileName, fileName, PATH_MAX, nls_codepage); name_len++; /* trailing null */ name_len *= 2; @@ -3759,7 +3759,7 @@ setPermsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -3904,7 +3904,7 @@ QAllEAsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -4047,7 +4047,7 @@ QEARetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -4194,7 +4194,7 @@ SetEARetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; -- cgit v1.2.3 From e74d633dc5f56bf059f870370b2f36b021298652 Mon Sep 17 00:00:00 2001 From: Goffredo Baroncelli Date: Tue, 31 May 2005 14:39:31 -0700 Subject: [PATCH] UDF filesystem: array '__mon_yday' declared as not static in fs/udf/udftime.c the global array '__mon_yday' is not static, and it conflicts with the glibc one when the kernel is compiled as user mode. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/udf/udftime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c index 457a8fe28575..85d8dbe843f1 100644 --- a/fs/udf/udftime.c +++ b/fs/udf/udftime.c @@ -46,7 +46,7 @@ #endif /* How many days come before each month (0-12). */ -const unsigned short int __mon_yday[2][13] = +static const unsigned short int __mon_yday[2][13] = { /* Normal years. */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, -- cgit v1.2.3 From 5f64f73957f6cae3222f97f2599199ee562f7f3f Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 1 Jun 2005 17:07:27 +1000 Subject: [PATCH] ppc32/ppc64: cleanup /proc/device-tree This cleans up the /proc/device-tree representation of the Open Firmware device-tree on ppc and ppc64. It does the following things: - Workaround an issue in some Apple device-trees where a property may exist with the same name as a child node of the parent. We now simply "drop" the property instead of creating duplicate entries in /proc with random result... - Do not try to chop off the "@0" at the end of a node name whose unit address is 0. This is not useful, inconsistent, and the code was buggy and didn't always work anyway. - Do not create symlinks for the short name and unit address parts of a node. These were never really used, bloated the memory footprint of the device-tree with useless struct proc_dir_entry and their matching dentry and inode cache bloat. This results in smaller code, smaller memory footprint, and a more accurate view of the tree presented to userland. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/pSeries_reconfig.c | 8 --- fs/proc/proc_devtree.c | 105 +++++++++++++---------------------- include/asm-ppc64/prom.h | 13 +---- 3 files changed, 39 insertions(+), 87 deletions(-) (limited to 'fs') diff --git a/arch/ppc64/kernel/pSeries_reconfig.c b/arch/ppc64/kernel/pSeries_reconfig.c index cb5443f2e49b..dc2a69d412a2 100644 --- a/arch/ppc64/kernel/pSeries_reconfig.c +++ b/arch/ppc64/kernel/pSeries_reconfig.c @@ -47,14 +47,6 @@ static void remove_node_proc_entries(struct device_node *np) remove_proc_entry(pp->name, np->pde); pp = pp->next; } - - /* Assuming that symlinks have the same parent directory as - * np->pde. - */ - if (np->name_link) - remove_proc_entry(np->name_link->name, parent->pde); - if (np->addr_link) - remove_proc_entry(np->addr_link->name, parent->pde); if (np->pde) remove_proc_entry(np->pde->name, parent->pde); } diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 67423c696c0a..6fd57f154197 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c @@ -12,15 +12,8 @@ #include #ifndef HAVE_ARCH_DEVTREE_FIXUPS -static inline void set_node_proc_entry(struct device_node *np, struct proc_dir_entry *de) -{ -} - -static void inline set_node_name_link(struct device_node *np, struct proc_dir_entry *de) -{ -} - -static void inline set_node_addr_link(struct device_node *np, struct proc_dir_entry *de) +static inline void set_node_proc_entry(struct device_node *np, + struct proc_dir_entry *de) { } #endif @@ -58,89 +51,67 @@ static int property_read_proc(char *page, char **start, off_t off, /* * Process a node, adding entries for its children and its properties. */ -void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *de) +void proc_device_tree_add_node(struct device_node *np, + struct proc_dir_entry *de) { struct property *pp; struct proc_dir_entry *ent; - struct device_node *child, *sib; - const char *p, *at; - int l; - struct proc_dir_entry *list, **lastp, *al; + struct device_node *child; + struct proc_dir_entry *list = NULL, **lastp; + const char *p; set_node_proc_entry(np, de); lastp = &list; - for (pp = np->properties; pp != 0; pp = pp->next) { - /* - * Unfortunately proc_register puts each new entry - * at the beginning of the list. So we rearrange them. - */ - ent = create_proc_read_entry(pp->name, strncmp(pp->name, "security-", 9) ? - S_IRUGO : S_IRUSR, de, property_read_proc, pp); - if (ent == 0) - break; - if (!strncmp(pp->name, "security-", 9)) - ent->size = 0; /* don't leak number of password chars */ - else - ent->size = pp->length; - *lastp = ent; - lastp = &ent->next; - } - child = NULL; - while ((child = of_get_next_child(np, child))) { + for (child = NULL; (child = of_get_next_child(np, child));) { p = strrchr(child->full_name, '/'); if (!p) p = child->full_name; else ++p; - /* chop off '@0' if the name ends with that */ - l = strlen(p); - if (l > 2 && p[l-2] == '@' && p[l-1] == '0') - l -= 2; ent = proc_mkdir(p, de); if (ent == 0) break; *lastp = ent; + ent->next = NULL; lastp = &ent->next; proc_device_tree_add_node(child, ent); - - /* - * If we left the address part on the name, consider - * adding symlinks from the name and address parts. - */ - if (p[l] != 0 || (at = strchr(p, '@')) == 0) - continue; - + } + of_node_put(child); + for (pp = np->properties; pp != 0; pp = pp->next) { /* - * If this is the first node with a given name property, - * add a symlink with the name property as its name. + * Yet another Apple device-tree bogosity: on some machines, + * they have properties & nodes with the same name. Those + * properties are quite unimportant for us though, thus we + * simply "skip" them here, but we do have to check. */ - sib = NULL; - while ((sib = of_get_next_child(np, sib)) && sib != child) - if (sib->name && strcmp(sib->name, child->name) == 0) - break; - if (sib == child && strncmp(p, child->name, l) != 0) { - al = proc_symlink(child->name, de, ent->name); - if (al == 0) { - of_node_put(sib); + for (ent = list; ent != NULL; ent = ent->next) + if (!strcmp(ent->name, pp->name)) break; - } - set_node_name_link(child, al); - *lastp = al; - lastp = &al->next; + if (ent != NULL) { + printk(KERN_WARNING "device-tree: property \"%s\" name" + " conflicts with node in %s\n", pp->name, + np->full_name); + continue; } - of_node_put(sib); + /* - * Add another directory with the @address part as its name. + * Unfortunately proc_register puts each new entry + * at the beginning of the list. So we rearrange them. */ - al = proc_symlink(at, de, ent->name); - if (al == 0) + ent = create_proc_read_entry(pp->name, + strncmp(pp->name, "security-", 9) + ? S_IRUGO : S_IRUSR, de, + property_read_proc, pp); + if (ent == 0) break; - set_node_addr_link(child, al); - *lastp = al; - lastp = &al->next; + if (!strncmp(pp->name, "security-", 9)) + ent->size = 0; /* don't leak number of password chars */ + else + ent->size = pp->length; + ent->next = NULL; + *lastp = ent; + lastp = &ent->next; } - of_node_put(child); - *lastp = NULL; de->subdir = list; } diff --git a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h index 2440a2c90ae9..04b1a84f7ca3 100644 --- a/include/asm-ppc64/prom.h +++ b/include/asm-ppc64/prom.h @@ -147,9 +147,7 @@ struct device_node { struct device_node *sibling; struct device_node *next; /* next device of same type */ struct device_node *allnext; /* next in list of all nodes */ - struct proc_dir_entry *pde; /* this node's proc directory */ - struct proc_dir_entry *name_link; /* name symlink */ - struct proc_dir_entry *addr_link; /* addr symlink */ + struct proc_dir_entry *pde; /* this node's proc directory */ struct kref kref; unsigned long _flags; }; @@ -174,15 +172,6 @@ static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_e dn->pde = de; } -static void inline set_node_name_link(struct device_node *dn, struct proc_dir_entry *de) -{ - dn->name_link = de; -} - -static void inline set_node_addr_link(struct device_node *dn, struct proc_dir_entry *de) -{ - dn->addr_link = de; -} /* OBSOLETE: Old stlye node lookup */ extern struct device_node *find_devices(const char *name); -- cgit v1.2.3 From 00ea81459c279f14a7b344320a71c94f60f88929 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 2 Jun 2005 14:02:00 -0700 Subject: [PATCH] ext3: fix log_do_checkpoint() assertion failure Fix possible false assertion failure in log_do_checkpoint(). We might fail to detect that we actually made a progress when cleaning up the checkpoint lists if we don't retry after writing something to disk. The patch was confirmed to fix observed assertion failures for several users. When we flushed some buffers we need to retry scanning the list. Otherwise we can fail to detect our progress. Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd/checkpoint.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 98d830401c56..58133ab9457e 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c @@ -339,8 +339,10 @@ int log_do_checkpoint(journal_t *journal) } } while (jh != last_jh && !retry); - if (batch_count) + if (batch_count) { __flush_batch(journal, bhs, &batch_count); + retry = 1; + } /* * If someone cleaned up this transaction while we slept, we're -- cgit v1.2.3 From 7e3b11a9be6ac94bf4af81757b6a10e7e65b846f Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 2 Jun 2005 14:02:01 -0700 Subject: [PATCH] ext3: fix list scanning in __cleanup_transaction Fix a bug in list scanning that can cause us to skip the last buffer on the checkpoint list (and hence fail to do any progress under some rather unfavorable conditions). The problem is we first do jh=next_jh and then test } while (jh!=last_jh); Hence we skip the last buffer on the list (if it was not the only buffer on the list). As we already do jh=next_jh; in the beginning of the loop we are safe to just remove the assignment in the end. It can happen that 'jh' will be freed at the point we test jh != last_jh but that does not matter as we never *dereference* the pointer. Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd/checkpoint.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs') diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 58133ab9457e..5a97e346bd95 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c @@ -188,7 +188,6 @@ static int __cleanup_transaction(journal_t *journal, transaction_t *transaction) } else { jbd_unlock_bh_state(bh); } - jh = next_jh; } while (jh != last_jh); return ret; -- cgit v1.2.3 From 854715be73b221596c7127d4042e1120d4539e19 Mon Sep 17 00:00:00 2001 From: Qu Fuping Date: Sat, 4 Jun 2005 15:43:29 -0700 Subject: [PATCH] mpage_end_io_write() I/O error handling fix When fsync() runs wait_on_page_writeback_range() it only inspects pages which are actually under I/O (PAGECACHE_TAG_WRITEBACK). If a page completed I/O prior to wait_on_page_writeback_range() looking at it, it is supposed to have recorded its I/O error state in the address_space. But mpage_mpage_end_io_write() forgot to set the address_space error flag in this case. Signed-off-by: Qu Fuping Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/mpage.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/mpage.c b/fs/mpage.c index b92c0e64aefa..bb9aebe93862 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -79,8 +79,11 @@ static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err) if (--bvec >= bio->bi_io_vec) prefetchw(&bvec->bv_page->flags); - if (!uptodate) + if (!uptodate){ SetPageError(page); + if (page->mapping) + set_bit(AS_EIO, &page->mapping->flags); + } end_page_writeback(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); -- cgit v1.2.3 From 90ebe5654febe3555a2516d51d3d251226d35fdb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:35:58 -0700 Subject: [PATCH] namei fixes OK, here comes a patch series that hopefully should close all too-early-mntput() races in fs/namei.c. Entire area is convoluted as hell, so I'm splitting that series into _very_ small chunks. Patches alread in the tree close only (very wide) races in following symlinks (see "busy inodes after umount" thread some time ago). Unfortunately, quite a few narrower races of the same nature were not closed. Hopefully this should take care of all of them. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index dd78f01b6de8..abeec34e7553 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -493,6 +493,11 @@ fail: return PTR_ERR(link); } +struct path { + struct vfsmount *mnt; + struct dentry *dentry; +}; + static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) { int error; @@ -518,7 +523,7 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) * Without that kind of total limit, nasty chains of consecutive * symlinks can cause almost arbitrarily long lookups. */ -static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) +static inline int do_follow_link(struct path *path, struct nameidata *nd) { int err = -ELOOP; if (current->link_count >= MAX_NESTED_LINKS) @@ -527,13 +532,13 @@ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) goto loop; BUG_ON(nd->depth >= MAX_NESTED_LINKS); cond_resched(); - err = security_inode_follow_link(dentry, nd); + err = security_inode_follow_link(path->dentry, nd); if (err) goto loop; current->link_count++; current->total_link_count++; nd->depth++; - err = __do_follow_link(dentry, nd); + err = __do_follow_link(path->dentry, nd); current->link_count--; nd->depth--; return err; @@ -641,11 +646,6 @@ static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry) follow_mount(mnt, dentry); } -struct path { - struct vfsmount *mnt; - struct dentry *dentry; -}; - /* * It's more convoluted than I'd like it to be, but... it's still fairly * small and for now I'd prefer to have fast path as straight as possible. @@ -784,7 +784,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) if (inode->i_op->follow_link) { mntget(next.mnt); - err = do_follow_link(next.dentry, nd); + err = do_follow_link(&next, nd); dput(next.dentry); mntput(next.mnt); if (err) @@ -838,7 +838,7 @@ last_component: if ((lookup_flags & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { mntget(next.mnt); - err = do_follow_link(next.dentry, nd); + err = do_follow_link(&next, nd); dput(next.dentry); mntput(next.mnt); if (err) -- cgit v1.2.3 From 5f92b3bcec0fa2e2d775b589850097f9dc6b2de2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:35:59 -0700 Subject: [PATCH] namei fixes (2/19) All callers of do_follow_link() do mntget() right before it and dput()+mntput() right after. These calls are moved inside do_follow_link() now. Obviously equivalent transformation. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index abeec34e7553..12d75ed214f6 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -526,6 +526,7 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) static inline int do_follow_link(struct path *path, struct nameidata *nd) { int err = -ELOOP; + mntget(path->mnt); if (current->link_count >= MAX_NESTED_LINKS) goto loop; if (current->total_link_count >= 40) @@ -541,9 +542,13 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) err = __do_follow_link(path->dentry, nd); current->link_count--; nd->depth--; + dput(path->dentry); + mntput(path->mnt); return err; loop: path_release(nd); + dput(path->dentry); + mntput(path->mnt); return err; } @@ -783,10 +788,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) goto out_dput; if (inode->i_op->follow_link) { - mntget(next.mnt); err = do_follow_link(&next, nd); - dput(next.dentry); - mntput(next.mnt); if (err) goto return_err; err = -ENOENT; @@ -837,10 +839,7 @@ last_component: inode = next.dentry->d_inode; if ((lookup_flags & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { - mntget(next.mnt); err = do_follow_link(&next, nd); - dput(next.dentry); - mntput(next.mnt); if (err) goto return_err; inode = nd->dentry->d_inode; -- cgit v1.2.3 From 4e7506e4dd9e40c189fcbec95d5dbc92f2e5926a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:00 -0700 Subject: [PATCH] namei fixes (3/19) Replaced struct dentry *dentry in namei with struct path path. All uses of dentry replaced with path.dentry there. Obviously equivalent transformation. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 12d75ed214f6..167f19b5e51a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1397,7 +1397,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) { int acc_mode, error = 0; - struct dentry *dentry; + struct path path; struct dentry *dir; int count = 0; @@ -1441,23 +1441,23 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) dir = nd->dentry; nd->flags &= ~LOOKUP_PARENT; down(&dir->d_inode->i_sem); - dentry = __lookup_hash(&nd->last, nd->dentry, nd); + path.dentry = __lookup_hash(&nd->last, nd->dentry, nd); do_last: - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) { + error = PTR_ERR(path.dentry); + if (IS_ERR(path.dentry)) { up(&dir->d_inode->i_sem); goto exit; } /* Negative dentry, just create the file */ - if (!dentry->d_inode) { + if (!path.dentry->d_inode) { if (!IS_POSIXACL(dir->d_inode)) mode &= ~current->fs->umask; - error = vfs_create(dir->d_inode, dentry, mode, nd); + error = vfs_create(dir->d_inode, path.dentry, mode, nd); up(&dir->d_inode->i_sem); dput(nd->dentry); - nd->dentry = dentry; + nd->dentry = path.dentry; if (error) goto exit; /* Don't check for write permission, don't truncate */ @@ -1475,22 +1475,22 @@ do_last: if (flag & O_EXCL) goto exit_dput; - if (d_mountpoint(dentry)) { + if (d_mountpoint(path.dentry)) { error = -ELOOP; if (flag & O_NOFOLLOW) goto exit_dput; - while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry)); + while (__follow_down(&nd->mnt,&path.dentry) && d_mountpoint(path.dentry)); } error = -ENOENT; - if (!dentry->d_inode) + if (!path.dentry->d_inode) goto exit_dput; - if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link) + if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link) goto do_link; dput(nd->dentry); - nd->dentry = dentry; + nd->dentry = path.dentry; error = -EISDIR; - if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) + if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode)) goto exit; ok: error = may_open(nd, acc_mode, flag); @@ -1499,7 +1499,7 @@ ok: return 0; exit_dput: - dput(dentry); + dput(path.dentry); exit: path_release(nd); return error; @@ -1519,16 +1519,16 @@ do_link: * are done. Procfs-like symlinks just set LAST_BIND. */ nd->flags |= LOOKUP_PARENT; - error = security_inode_follow_link(dentry, nd); + error = security_inode_follow_link(path.dentry, nd); if (error) goto exit_dput; - error = __do_follow_link(dentry, nd); - dput(dentry); + error = __do_follow_link(path.dentry, nd); + dput(path.dentry); if (error) return error; nd->flags &= ~LOOKUP_PARENT; if (nd->last_type == LAST_BIND) { - dentry = nd->dentry; + path.dentry = nd->dentry; goto ok; } error = -EISDIR; @@ -1545,7 +1545,7 @@ do_link: } dir = nd->dentry; down(&dir->d_inode->i_sem); - dentry = __lookup_hash(&nd->last, nd->dentry, nd); + path.dentry = __lookup_hash(&nd->last, nd->dentry, nd); putname(nd->last.name); goto do_last; } -- cgit v1.2.3 From d73ffe16b8baafae6e9249acee6b50c24099c6de Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:01 -0700 Subject: [PATCH] namei fixes (4/19) path.mnt in open_namei() set to mirror nd->mnt. nd->mnt is set in 3 places in that function - path_lookup() in the beginning, __follow_down() loop after do_last: and __do_follow_link() call after do_link:. We set path.mnt to nd->mnt after path_lookup() and __do_follow_link(). In __follow_down() loop we use &path.mnt instead of &nd->mnt and set nd->mnt to path.mnt immediately after that loop. Obviously equivalent transformation. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 167f19b5e51a..e42f7c35545a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1442,6 +1442,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) nd->flags &= ~LOOKUP_PARENT; down(&dir->d_inode->i_sem); path.dentry = __lookup_hash(&nd->last, nd->dentry, nd); + path.mnt = nd->mnt; do_last: error = PTR_ERR(path.dentry); @@ -1479,7 +1480,8 @@ do_last: error = -ELOOP; if (flag & O_NOFOLLOW) goto exit_dput; - while (__follow_down(&nd->mnt,&path.dentry) && d_mountpoint(path.dentry)); + while (__follow_down(&path.mnt,&path.dentry) && d_mountpoint(path.dentry)); + nd->mnt = path.mnt; } error = -ENOENT; if (!path.dentry->d_inode) @@ -1524,6 +1526,7 @@ do_link: goto exit_dput; error = __do_follow_link(path.dentry, nd); dput(path.dentry); + path.mnt = nd->mnt; if (error) return error; nd->flags &= ~LOOKUP_PARENT; -- cgit v1.2.3 From 1be4a0900be5d2c2fd9cd012e3a153e1ea47b96a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:01 -0700 Subject: [PATCH] namei fixes (5/19) fix for too early mntput() in open_namei() - we pin path.mnt down for the duration of __do_follow_link(). Otherwise we could get the fs where our symlink lived unmounted while we were in __do_follow_link(). That would end up with dentry of symlink staying pinned down through the fs shutdown. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index e42f7c35545a..020fb8c8d1cd 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1524,8 +1524,10 @@ do_link: error = security_inode_follow_link(path.dentry, nd); if (error) goto exit_dput; + mntget(path.mnt); error = __do_follow_link(path.dentry, nd); dput(path.dentry); + mntput(path.mnt); path.mnt = nd->mnt; if (error) return error; -- cgit v1.2.3 From 839d9f93c9f1623fb37234d464d739617879d97e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:02 -0700 Subject: [PATCH] namei fixes (6/19) mntget(path->mnt) in do_follow_link() moved down to right before the __do_follow_link() call and rigth after loop: resp. dput()+mntput() on non-ELOOP branch moved up to right after __do_follow_link() call. resulting loop: mntget(path->mnt); path_release(nd); dput(path->mnt); mntput(path->mnt); replaced with equivalent dput(path->mnt); path_release(nd); Equivalent transformations - the reason why we have that mntget() is that __do_follow_link() can drop a reference to nd->mnt and that's what holds path->mnt. So that call can happen at any point prior to __do_follow_link() touching nd->mnt. The rest is obvious. NOTE: current tree relies on symlinks *never* being mounted on anything. It's not hard to get rid of that assumption (actually, that will come for free later in the series). For now we are just not making the situation worse than it is. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 020fb8c8d1cd..519900d83bcb 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -526,7 +526,6 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) static inline int do_follow_link(struct path *path, struct nameidata *nd) { int err = -ELOOP; - mntget(path->mnt); if (current->link_count >= MAX_NESTED_LINKS) goto loop; if (current->total_link_count >= 40) @@ -539,16 +538,16 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) current->link_count++; current->total_link_count++; nd->depth++; + mntget(path->mnt); err = __do_follow_link(path->dentry, nd); - current->link_count--; - nd->depth--; dput(path->dentry); mntput(path->mnt); + current->link_count--; + nd->depth--; return err; loop: - path_release(nd); dput(path->dentry); - mntput(path->mnt); + path_release(nd); return err; } -- cgit v1.2.3 From cd4e91d3bca8d5527289f5984cf32e9fe6fb8293 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:03 -0700 Subject: [PATCH] namei fixes (7/19) The first argument of __do_follow_link() switched to struct path * (__do_follow_link(path->dentry, ...) -> __do_follow_link(path, ...)). All callers have the same calls of mntget() right before and dput()/mntput() right after __do_follow_link(); these calls have been moved inside. Obviously equivalent transformations. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 519900d83bcb..18ea0606145e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -498,12 +498,15 @@ struct path { struct dentry *dentry; }; -static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) +static inline int __do_follow_link(struct path *path, struct nameidata *nd) { int error; + struct dentry *dentry = path->dentry; touch_atime(nd->mnt, dentry); nd_set_link(nd, NULL); + + mntget(path->mnt); error = dentry->d_inode->i_op->follow_link(dentry, nd); if (!error) { char *s = nd_get_link(nd); @@ -512,6 +515,8 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) if (dentry->d_inode->i_op->put_link) dentry->d_inode->i_op->put_link(dentry, nd); } + dput(dentry); + mntput(path->mnt); return error; } @@ -538,10 +543,7 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) current->link_count++; current->total_link_count++; nd->depth++; - mntget(path->mnt); - err = __do_follow_link(path->dentry, nd); - dput(path->dentry); - mntput(path->mnt); + err = __do_follow_link(path, nd); current->link_count--; nd->depth--; return err; @@ -1523,10 +1525,7 @@ do_link: error = security_inode_follow_link(path.dentry, nd); if (error) goto exit_dput; - mntget(path.mnt); - error = __do_follow_link(path.dentry, nd); - dput(path.dentry); - mntput(path.mnt); + error = __do_follow_link(&path, nd); path.mnt = nd->mnt; if (error) return error; -- cgit v1.2.3 From d671d5e51400aab03c713a16ce3545aa81ad7b1c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:04 -0700 Subject: [PATCH] namei fixes (8/19) In open_namei() we never use path.mnt or path.dentry after exit: or ok:. Assignment of path.dentry in case of LAST_BIND is dead code and only obfuscates already convoluted function; assignment of path.mnt after __do_follow_link() can be moved down to the place where we set path.dentry. Obviously equivalent transformations, just to clean the air a bit in that region. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 18ea0606145e..3d08478d3130 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1526,14 +1526,11 @@ do_link: if (error) goto exit_dput; error = __do_follow_link(&path, nd); - path.mnt = nd->mnt; if (error) return error; nd->flags &= ~LOOKUP_PARENT; - if (nd->last_type == LAST_BIND) { - path.dentry = nd->dentry; + if (nd->last_type == LAST_BIND) goto ok; - } error = -EISDIR; if (nd->last_type != LAST_NORM) goto exit; @@ -1549,6 +1546,7 @@ do_link: dir = nd->dentry; down(&dir->d_inode->i_sem); path.dentry = __lookup_hash(&nd->last, nd->dentry, nd); + path.mnt = nd->mnt; putname(nd->last.name); goto do_last; } -- cgit v1.2.3 From 463ffb2e9d39c2a3fd8c3c1d4a34e01f2078f972 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:05 -0700 Subject: [PATCH] namei fixes (9/19) New helper: __follow_mount(struct path *path). Same as follow_mount(), except that we do *not* do mntput() after the first lookup_mnt(). IOW, original path->mnt stays pinned down. We also take care to do dput() before mntput() in the loop body (follow_mount() also needs that reordering, but that will be done later in the series). The following are equivalent, assuming that path.mnt == x: (1) follow_mount(&path.mnt, &path.dentry) (2) __follow_mount(&path); if (path->mnt != x) mntput(x); (3) if (__follow_mount(&path)) mntput(x); Callers of follow_mount() in __link_path_walk() converted to (2). Equivalent transformation + fix for too-late-mntput() race in __follow_mount() loop. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 3d08478d3130..23a1ad467976 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -576,6 +576,23 @@ int follow_up(struct vfsmount **mnt, struct dentry **dentry) /* no need for dcache_lock, as serialization is taken care in * namespace.c */ +static int __follow_mount(struct path *path) +{ + int res = 0; + while (d_mountpoint(path->dentry)) { + struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry); + if (!mounted) + break; + dput(path->dentry); + if (res) + mntput(path->mnt); + path->mnt = mounted; + path->dentry = dget(mounted->mnt_root); + res = 1; + } + return res; +} + static int follow_mount(struct vfsmount **mnt, struct dentry **dentry) { int res = 0; @@ -778,7 +795,9 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) if (err) break; /* Check mountpoints.. */ - follow_mount(&next.mnt, &next.dentry); + __follow_mount(&next); + if (nd->mnt != next.mnt) + mntput(nd->mnt); err = -ENOENT; inode = next.dentry->d_inode; @@ -836,7 +855,9 @@ last_component: err = do_lookup(nd, &this, &next); if (err) break; - follow_mount(&next.mnt, &next.dentry); + __follow_mount(&next); + if (nd->mnt != next.mnt) + mntput(nd->mnt); inode = next.dentry->d_inode; if ((lookup_flags & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { -- cgit v1.2.3 From e13b210f6f7bdc44dfee0a9bbd633a32db0d6333 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:06 -0700 Subject: [PATCH] namei fixes (10/19) In open_namei(), __follow_down() loop turned into __follow_mount(). Instead of if we are on a mountpoint dentry if O_NOFOLLOW checks fail drop path.dentry drop nd return do equivalent of follow_mount(&path.mnt, &path.dentry) nd->mnt = path.mnt we do if __follow_mount(path) had, indeed, traversed mountpoint /* now both nd->mnt and path.mnt are pinned down */ if O_NOFOLLOW checks fail drop path.dentry drop path.mnt drop nd return mntput(nd->mnt) nd->mnt = path.mnt Now __follow_down() can be folded into follow_down() - no other callers left. We need to reorder dput()/mntput() there - same problem as in follow_mount(). Equivalent transformation + fix for a bug in O_NOFOLLOW handling - we used to get -ELOOP if we had the same fs mounted on /foo and /bar, had something bound on /bar/baz and tried to open /foo/baz with O_NOFOLLOW. And fix of too-early-mntput() race in follow_down() Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 23a1ad467976..935b08d8dcd8 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -612,26 +612,21 @@ static int follow_mount(struct vfsmount **mnt, struct dentry **dentry) /* no need for dcache_lock, as serialization is taken care in * namespace.c */ -static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry) +int follow_down(struct vfsmount **mnt, struct dentry **dentry) { struct vfsmount *mounted; mounted = lookup_mnt(*mnt, *dentry); if (mounted) { + dput(*dentry); mntput(*mnt); *mnt = mounted; - dput(*dentry); *dentry = dget(mounted->mnt_root); return 1; } return 0; } -int follow_down(struct vfsmount **mnt, struct dentry **dentry) -{ - return __follow_down(mnt,dentry); -} - static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry) { while(1) { @@ -1498,11 +1493,14 @@ do_last: if (flag & O_EXCL) goto exit_dput; - if (d_mountpoint(path.dentry)) { + if (__follow_mount(&path)) { error = -ELOOP; - if (flag & O_NOFOLLOW) - goto exit_dput; - while (__follow_down(&path.mnt,&path.dentry) && d_mountpoint(path.dentry)); + if (flag & O_NOFOLLOW) { + dput(path.dentry); + mntput(path.mnt); + goto exit; + } + mntput(nd->mnt); nd->mnt = path.mnt; } error = -ENOENT; -- cgit v1.2.3 From 2f12dbfbb6286c725c283a169f8f05e89a86848b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:07 -0700 Subject: [PATCH] namei fixes (11/19) shifted conditional mntput() calls in __link_path_walk() downstream. Obviously equivalent transformation. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 935b08d8dcd8..907a3f2b4c9c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -791,8 +791,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) break; /* Check mountpoints.. */ __follow_mount(&next); - if (nd->mnt != next.mnt) - mntput(nd->mnt); err = -ENOENT; inode = next.dentry->d_inode; @@ -803,6 +801,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) goto out_dput; if (inode->i_op->follow_link) { + if (nd->mnt != next.mnt) + mntput(nd->mnt); err = do_follow_link(&next, nd); if (err) goto return_err; @@ -815,6 +815,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) break; } else { dput(nd->dentry); + if (nd->mnt != next.mnt) + mntput(nd->mnt); nd->mnt = next.mnt; nd->dentry = next.dentry; } @@ -851,17 +853,19 @@ last_component: if (err) break; __follow_mount(&next); - if (nd->mnt != next.mnt) - mntput(nd->mnt); inode = next.dentry->d_inode; if ((lookup_flags & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { + if (next.mnt != nd->mnt) + mntput(nd->mnt); err = do_follow_link(&next, nd); if (err) goto return_err; inode = nd->dentry->d_inode; } else { dput(nd->dentry); + if (nd->mnt != next.mnt) + mntput(nd->mnt); nd->mnt = next.mnt; nd->dentry = next.dentry; } @@ -901,6 +905,8 @@ return_base: return 0; out_dput: dput(next.dentry); + if (nd->mnt != next.mnt) + mntput(nd->mnt); break; } path_release(nd); -- cgit v1.2.3 From a15a3f6fc67d910f43098acec6e19d25a37d7cb9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:08 -0700 Subject: [PATCH] namei fixes (12/19) In open_namei() we take mntput(nd->mnt);nd->mnt=path.mnt; out of the if (__follow_mount(...)), making it conditional on nd->mnt != path.mnt instead. Then we shift the result downstream. Equivalent transformations. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 907a3f2b4c9c..37fcf941fa3f 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1506,8 +1506,6 @@ do_last: mntput(path.mnt); goto exit; } - mntput(nd->mnt); - nd->mnt = path.mnt; } error = -ENOENT; if (!path.dentry->d_inode) @@ -1517,6 +1515,9 @@ do_last: dput(nd->dentry); nd->dentry = path.dentry; + if (nd->mnt != path.mnt) + mntput(nd->mnt); + nd->mnt = path.mnt; error = -EISDIR; if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode)) goto exit; @@ -1528,6 +1529,9 @@ ok: exit_dput: dput(path.dentry); + if (nd->mnt != path.mnt) + mntput(nd->mnt); + nd->mnt = path.mnt; exit: path_release(nd); return error; @@ -1550,6 +1554,9 @@ do_link: error = security_inode_follow_link(path.dentry, nd); if (error) goto exit_dput; + if (nd->mnt != path.mnt) + mntput(nd->mnt); + nd->mnt = path.mnt; error = __do_follow_link(&path, nd); if (error) return error; -- cgit v1.2.3 From ba7a4c1a76f56c607560f1676680ff491747bdae Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:08 -0700 Subject: [PATCH] namei fixes (13/19) In open_namei() exit_dput: we have mntput() done in the wrong order - if nd->mnt != path.mnt we end up doing mntput(nd->mnt); nd->mnt = path.mnt; dput(nd->dentry); mntput(nd->mnt); which drops nd->dentry too late. Fixed by having path.mnt go first. That allows to switch O_NOFOLLOW under if (__follow_mount(...)) back to exit_dput, while we are at it. Fix for early-mntput() race + equivalent transformation. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 37fcf941fa3f..5153f57ee6b3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1501,11 +1501,8 @@ do_last: if (__follow_mount(&path)) { error = -ELOOP; - if (flag & O_NOFOLLOW) { - dput(path.dentry); - mntput(path.mnt); - goto exit; - } + if (flag & O_NOFOLLOW) + goto exit_dput; } error = -ENOENT; if (!path.dentry->d_inode) @@ -1530,8 +1527,7 @@ ok: exit_dput: dput(path.dentry); if (nd->mnt != path.mnt) - mntput(nd->mnt); - nd->mnt = path.mnt; + mntput(path.mnt); exit: path_release(nd); return error; -- cgit v1.2.3 From 4b7b9772e4c3d87e649d4c419d2487aacf1235aa Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:10 -0700 Subject: [PATCH] namei fixes (14/19) shifted conditional mntput() into do_follow_link() - all callers were doing the same thing. Obviously equivalent transformation. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 5153f57ee6b3..411bb3243c36 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -543,11 +543,15 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) current->link_count++; current->total_link_count++; nd->depth++; + if (path->mnt != nd->mnt) + mntput(nd->mnt); err = __do_follow_link(path, nd); current->link_count--; nd->depth--; return err; loop: + if (path->mnt != nd->mnt) + mntput(nd->mnt); dput(path->dentry); path_release(nd); return err; @@ -801,8 +805,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) goto out_dput; if (inode->i_op->follow_link) { - if (nd->mnt != next.mnt) - mntput(nd->mnt); err = do_follow_link(&next, nd); if (err) goto return_err; @@ -856,8 +858,6 @@ last_component: inode = next.dentry->d_inode; if ((lookup_flags & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { - if (next.mnt != nd->mnt) - mntput(nd->mnt); err = do_follow_link(&next, nd); if (err) goto return_err; -- cgit v1.2.3 From d9d29a29669f96903d9950bb881c2a393fd33849 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:11 -0700 Subject: [PATCH] namei fixes (15/19) Getting rid of sloppy logics: a) in do_follow_link() we have the wrong vfsmount dropped if our symlink had been mounted on something. Currently it worls only because we never get such situation (modulo filesystem playing dirty tricks on us). And it obfuscates already convoluted logics... b) same goes for open_namei(). c) in __link_path_walk() we have another "it should never happen" sloppiness - out_dput: there does double-free on underlying vfsmount and leaks the covering one if we hit it just after crossing a mountpoint. Again, wrong vfsmount getting dropped. d) another too-early-mntput() race - in do_follow_mount() we need to postpone conditional mntput(path->mnt) until after dput(path->dentry). Again, this one happens only in it-currently-never-happens-unless-some-fs-plays-dirty scenario... Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 411bb3243c36..6a884682b0a7 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -544,15 +544,15 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) current->total_link_count++; nd->depth++; if (path->mnt != nd->mnt) - mntput(nd->mnt); + mntput(path->mnt); err = __do_follow_link(path, nd); current->link_count--; nd->depth--; return err; loop: - if (path->mnt != nd->mnt) - mntput(nd->mnt); dput(path->dentry); + if (path->mnt != nd->mnt) + mntput(path->mnt); path_release(nd); return err; } @@ -906,7 +906,7 @@ return_base: out_dput: dput(next.dentry); if (nd->mnt != next.mnt) - mntput(nd->mnt); + mntput(next.mnt); break; } path_release(nd); @@ -1551,8 +1551,7 @@ do_link: if (error) goto exit_dput; if (nd->mnt != path.mnt) - mntput(nd->mnt); - nd->mnt = path.mnt; + mntput(path.mnt); error = __do_follow_link(&path, nd); if (error) return error; -- cgit v1.2.3 From 39ca6d49759346d4710c759d443eec8048b27213 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:12 -0700 Subject: [PATCH] namei fixes (16/19) Conditional mntput() moved into __do_follow_link(). There it collapses with unconditional mntget() on the same sucker, closing another too-early-mntput() race. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 6a884682b0a7..444086d441e1 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -506,7 +506,8 @@ static inline int __do_follow_link(struct path *path, struct nameidata *nd) touch_atime(nd->mnt, dentry); nd_set_link(nd, NULL); - mntget(path->mnt); + if (path->mnt == nd->mnt) + mntget(path->mnt); error = dentry->d_inode->i_op->follow_link(dentry, nd); if (!error) { char *s = nd_get_link(nd); @@ -543,8 +544,6 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) current->link_count++; current->total_link_count++; nd->depth++; - if (path->mnt != nd->mnt) - mntput(path->mnt); err = __do_follow_link(path, nd); current->link_count--; nd->depth--; @@ -1550,8 +1549,6 @@ do_link: error = security_inode_follow_link(path.dentry, nd); if (error) goto exit_dput; - if (nd->mnt != path.mnt) - mntput(path.mnt); error = __do_follow_link(&path, nd); if (error) return error; -- cgit v1.2.3 From 58c465eba4d7ed307c4c7cb3382ba7ee565e8858 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:13 -0700 Subject: [PATCH] namei fixes (17/19) follow_mount() made void, reordered dput()/mntput() in it. follow_dotdot() switched from struct vfmount ** + struct dentry ** to struct nameidata *; callers updated. Equivalent transformation + fix for too-early-mntput() race. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 444086d441e1..36925ff307b3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -596,20 +596,17 @@ static int __follow_mount(struct path *path) return res; } -static int follow_mount(struct vfsmount **mnt, struct dentry **dentry) +static void follow_mount(struct vfsmount **mnt, struct dentry **dentry) { - int res = 0; while (d_mountpoint(*dentry)) { struct vfsmount *mounted = lookup_mnt(*mnt, *dentry); if (!mounted) break; + dput(*dentry); mntput(*mnt); *mnt = mounted; - dput(*dentry); *dentry = dget(mounted->mnt_root); - res = 1; } - return res; } /* no need for dcache_lock, as serialization is taken care in @@ -630,41 +627,41 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry) return 0; } -static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry) +static inline void follow_dotdot(struct nameidata *nd) { while(1) { struct vfsmount *parent; - struct dentry *old = *dentry; + struct dentry *old = nd->dentry; read_lock(¤t->fs->lock); - if (*dentry == current->fs->root && - *mnt == current->fs->rootmnt) { + if (nd->dentry == current->fs->root && + nd->mnt == current->fs->rootmnt) { read_unlock(¤t->fs->lock); break; } read_unlock(¤t->fs->lock); spin_lock(&dcache_lock); - if (*dentry != (*mnt)->mnt_root) { - *dentry = dget((*dentry)->d_parent); + if (nd->dentry != nd->mnt->mnt_root) { + nd->dentry = dget(nd->dentry->d_parent); spin_unlock(&dcache_lock); dput(old); break; } spin_unlock(&dcache_lock); spin_lock(&vfsmount_lock); - parent = (*mnt)->mnt_parent; - if (parent == *mnt) { + parent = nd->mnt->mnt_parent; + if (parent == nd->mnt) { spin_unlock(&vfsmount_lock); break; } mntget(parent); - *dentry = dget((*mnt)->mnt_mountpoint); + nd->dentry = dget(nd->mnt->mnt_mountpoint); spin_unlock(&vfsmount_lock); dput(old); - mntput(*mnt); - *mnt = parent; + mntput(nd->mnt); + nd->mnt = parent; } - follow_mount(mnt, dentry); + follow_mount(&nd->mnt, &nd->dentry); } /* @@ -772,7 +769,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) case 2: if (this.name[1] != '.') break; - follow_dotdot(&nd->mnt, &nd->dentry); + follow_dotdot(nd); inode = nd->dentry->d_inode; /* fallthrough */ case 1: @@ -839,7 +836,7 @@ last_component: case 2: if (this.name[1] != '.') break; - follow_dotdot(&nd->mnt, &nd->dentry); + follow_dotdot(nd); inode = nd->dentry->d_inode; /* fallthrough */ case 1: -- cgit v1.2.3 From 634ee7017b31e46e28c0bd2cb488213331bfd39a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:13 -0700 Subject: [PATCH] namei fixes (18/19) Cosmetical cleanups - __follow_mount() calls in __link_path_walk() absorbed into do_lookup(). Obviously equivalent transformation. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 36925ff307b3..5af7681e8ea3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -682,6 +682,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, done: path->mnt = mnt; path->dentry = dentry; + __follow_mount(path); return 0; need_lookup: @@ -789,8 +790,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) err = do_lookup(nd, &this, &next); if (err) break; - /* Check mountpoints.. */ - __follow_mount(&next); err = -ENOENT; inode = next.dentry->d_inode; @@ -850,7 +849,6 @@ last_component: err = do_lookup(nd, &this, &next); if (err) break; - __follow_mount(&next); inode = next.dentry->d_inode; if ((lookup_flags & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { -- cgit v1.2.3 From d671a1cbf7c7a5c5562106d39eb7f830ae5273ae Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2005 13:36:14 -0700 Subject: [PATCH] namei fixes (19/19) __do_follow_link() passes potentially worng vfsmount to touch_atime(). It matters only in (currently impossible) case of symlink mounted on something, but it's trivial to fix and that actually makes more sense. Signed-off-by: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 5af7681e8ea3..a7f7f44119b3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -503,7 +503,7 @@ static inline int __do_follow_link(struct path *path, struct nameidata *nd) int error; struct dentry *dentry = path->dentry; - touch_atime(nd->mnt, dentry); + touch_atime(path->mnt, dentry); nd_set_link(nd, NULL); if (path->mnt == nd->mnt) -- cgit v1.2.3 From 8f5bb0438b86d1a5393176ceeec2836fd469edf8 Mon Sep 17 00:00:00 2001 From: Yoshinori Sato Date: Mon, 6 Jun 2005 14:46:32 -0700 Subject: [PATCH] binfmt_flat mmap flag fix Make sure that binfmt_flat passes the correct flags into do_mmap(). nommu's validate_mmap_request() will simple return -EINVAL if we try and pass it a flags value of zero. Signed-off-by: Yoshinori Sato Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/binfmt_flat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index f0cd67d9d31b..c8998dc66882 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -520,7 +520,7 @@ static int load_flat_file(struct linux_binprm * bprm, DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); down_write(¤t->mm->mmap_sem); - textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, 0, 0); + textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_SHARED, 0); up_write(¤t->mm->mmap_sem); if (!textpos || textpos >= (unsigned long) -4096) { if (!textpos) @@ -532,7 +532,7 @@ static int load_flat_file(struct linux_binprm * bprm, down_write(¤t->mm->mmap_sem); realdatastart = do_mmap(0, 0, data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long), - PROT_READ|PROT_WRITE|PROT_EXEC, 0, 0); + PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0); up_write(¤t->mm->mmap_sem); if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) { @@ -574,7 +574,7 @@ static int load_flat_file(struct linux_binprm * bprm, down_write(¤t->mm->mmap_sem); textpos = do_mmap(0, 0, text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long), - PROT_READ | PROT_EXEC | PROT_WRITE, 0, 0); + PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); up_write(¤t->mm->mmap_sem); if (!textpos || textpos >= (unsigned long) -4096) { if (!textpos) -- cgit v1.2.3 From 1d6757fbff5bc86e94e59ab0d7bdd7e71351d839 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 7 Jun 2005 18:37:01 -0400 Subject: [PATCH] NFS: Fix lookup intent handling We should never apply a lookup intent to anything other than the last path component in an open(), create() or access() call. Introduce the helper nfs_lookup_check_intent() which always returns zero if LOOKUP_CONTINUE or LOOKUP_PARENT are set, and returns the intent flags if we're on the last component of the lookup. By doing so, we fix a bug in open(O_EXCL), where we may end up optimizing away a real lookup of the parent directory. Problem noticed by Linda Dunaphant Signed-off-by: Trond Myklebust Signed-off-by: Linus Torvalds --- fs/nfs/dir.c | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 73f96acd5d37..ff6155f5e8d9 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -528,19 +528,39 @@ static inline void nfs_renew_times(struct dentry * dentry) dentry->d_time = jiffies; } +/* + * Return the intent data that applies to this particular path component + * + * Note that the current set of intents only apply to the very last + * component of the path. + * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT. + */ +static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask) +{ + if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT)) + return 0; + return nd->flags & mask; +} + +/* + * Inode and filehandle revalidation for lookups. + * + * We force revalidation in the cases where the VFS sets LOOKUP_REVAL, + * or if the intent information indicates that we're about to open this + * particular file and the "nocto" mount flag is not set. + * + */ static inline int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd) { struct nfs_server *server = NFS_SERVER(inode); if (nd != NULL) { - int ndflags = nd->flags; /* VFS wants an on-the-wire revalidation */ - if (ndflags & LOOKUP_REVAL) + if (nd->flags & LOOKUP_REVAL) goto out_force; /* This is an open(2) */ - if ((ndflags & LOOKUP_OPEN) && - !(ndflags & LOOKUP_CONTINUE) && + if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 && !(server->flags & NFS_MOUNT_NOCTO)) goto out_force; } @@ -560,12 +580,8 @@ static inline int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { - int ndflags = 0; - - if (nd) - ndflags = nd->flags; /* Don't revalidate a negative dentry if we're creating a new file */ - if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE)) + if (nd != NULL && nfs_lookup_check_intent(nd, LOOKUP_CREATE) != 0) return 0; return !nfs_check_verifier(dir, dentry); } @@ -700,12 +716,16 @@ struct dentry_operations nfs_dentry_operations = { .d_iput = nfs_dentry_iput, }; +/* + * Use intent information to check whether or not we're going to do + * an O_EXCL create using this path component. + */ static inline int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) { if (NFS_PROTO(dir)->version == 2) return 0; - if (!nd || (nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_CREATE)) + if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0) return 0; return (nd->intent.open.flags & O_EXCL) != 0; } @@ -772,12 +792,13 @@ struct dentry_operations nfs4_dentry_operations = { .d_iput = nfs_dentry_iput, }; +/* + * Use intent information to determine whether we need to substitute + * the NFSv4-style stateful OPEN for the LOOKUP call + */ static int is_atomic_open(struct inode *dir, struct nameidata *nd) { - if (!nd) - return 0; - /* Check that we are indeed trying to open this file */ - if ((nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_OPEN)) + if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0) return 0; /* NFS does not (yet) have a stateful open for directories */ if (nd->flags & LOOKUP_DIRECTORY) -- cgit v1.2.3