From 1b20d672188bf80baef60d515a123f556871a5ce Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 9 May 2008 18:17:21 +0000 Subject: [CIFS] cifs_find_tcp_session cleanup This patch cleans up cifs_find_tcp_session so it become less indented. Also the error of skipping IPv6 matched addresses fixed. Signed-off-by: Cyrill Gorcunov Signed-off-by: Steve French --- fs/cifs/connect.c | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) (limited to 'fs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 791ca5c1a11..6b520aad7af 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1318,42 +1318,43 @@ cifs_parse_mount_options(char *options, const char *devname, static struct cifsSesInfo * cifs_find_tcp_session(struct in_addr *target_ip_addr, - struct in6_addr *target_ip6_addr, - char *userName, struct TCP_Server_Info **psrvTcp) + struct in6_addr *target_ip6_addr, + char *userName, struct TCP_Server_Info **psrvTcp) { struct list_head *tmp; struct cifsSesInfo *ses; + *psrvTcp = NULL; - read_lock(&GlobalSMBSeslock); + read_lock(&GlobalSMBSeslock); list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - if (ses->server) { - if ((target_ip_addr && - (ses->server->addr.sockAddr.sin_addr.s_addr - == target_ip_addr->s_addr)) || (target_ip6_addr - && memcmp(&ses->server->addr.sockAddr6.sin6_addr, - target_ip6_addr, sizeof(*target_ip6_addr)))) { - /* BB lock server and tcp session and increment - use count here?? */ - - /* found a match on the TCP session */ - *psrvTcp = ses->server; - - /* BB check if reconnection needed */ - if (strncmp - (ses->userName, userName, - MAX_USERNAME_SIZE) == 0){ - read_unlock(&GlobalSMBSeslock); - /* Found exact match on both TCP and - SMB sessions */ - return ses; - } - } + if (!ses->server) + continue; + + if (target_ip_addr && + ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr) + continue; + else if (target_ip6_addr && + memcmp(&ses->server->addr.sockAddr6.sin6_addr, + target_ip6_addr, sizeof(*target_ip6_addr))) + continue; + /* BB lock server and tcp session and increment use count here?? */ + + /* found a match on the TCP session */ + *psrvTcp = ses->server; + + /* BB check if reconnection needed */ + if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) { + read_unlock(&GlobalSMBSeslock); + /* Found exact match on both TCP and + SMB sessions */ + return ses; } /* else tcp and smb sessions need reconnection */ } read_unlock(&GlobalSMBSeslock); + return NULL; } -- cgit v1.2.3 From 02eadeffda169a45946c79270ec19f45eeafb8e7 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 9 May 2008 21:26:11 +0000 Subject: [CIFS] add local struct inode pointer to cifs_setattr Clean up cifs_setattr a bit by adding a local inode pointer, and changing all of the direntry->d_inode references to it. This also adds a bit of micro-optimization. d_inode shouldn't change over the life of this function, so we only need to dereference it once. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 2 +- fs/cifs/inode.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 6b520aad7af..96505086759 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1339,7 +1339,7 @@ cifs_find_tcp_session(struct in_addr *target_ip_addr, memcmp(&ses->server->addr.sockAddr6.sin6_addr, target_ip6_addr, sizeof(*target_ip6_addr))) continue; - /* BB lock server and tcp session and increment use count here?? */ + /* BB lock server and tcp session; increment use count here?? */ /* found a match on the TCP session */ *psrvTcp = ses->server; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 0d9d2e6d7af..d904a037c83 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1408,18 +1408,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) __u64 uid = 0xFFFFFFFFFFFFFFFFULL; __u64 gid = 0xFFFFFFFFFFFFFFFFULL; struct cifsInodeInfo *cifsInode; + struct inode *inode = direntry->d_inode; xid = GetXid(); 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); + cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { /* check if we have permission to change attrs */ - rc = inode_change_ok(direntry->d_inode, attrs); + rc = inode_change_ok(inode, attrs); if (rc < 0) { FreeXid(xid); return rc; @@ -1432,7 +1433,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) FreeXid(xid); return -ENOMEM; } - cifsInode = CIFS_I(direntry->d_inode); + cifsInode = CIFS_I(inode); if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { /* @@ -1443,9 +1444,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) will be truncated anyway? Also, should we error out here if the flush returns error? */ - rc = filemap_write_and_wait(direntry->d_inode->i_mapping); + rc = filemap_write_and_wait(inode->i_mapping); if (rc != 0) { - CIFS_I(direntry->d_inode)->write_behind_rc = rc; + cifsInode->write_behind_rc = rc; rc = 0; } } @@ -1521,9 +1522,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) */ if (rc == 0) { - rc = cifs_vmtruncate(direntry->d_inode, attrs->ia_size); - cifs_truncate_page(direntry->d_inode->i_mapping, - direntry->d_inode->i_size); + rc = cifs_vmtruncate(inode, attrs->ia_size); + cifs_truncate_page(inode->i_mapping, inode->i_size); } else goto cifs_setattr_exit; } @@ -1557,7 +1557,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) rc = 0; #ifdef CONFIG_CIFS_EXPERIMENTAL if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) - rc = mode_to_acl(direntry->d_inode, full_path, mode); + rc = mode_to_acl(inode, full_path, mode); else if ((mode & S_IWUGO) == 0) { #else if ((mode & S_IWUGO) == 0) { @@ -1665,7 +1665,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) /* do not need local check to inode_check_ok since the server does that */ if (!rc) - rc = inode_setattr(direntry->d_inode, attrs); + rc = inode_setattr(inode, attrs); cifs_setattr_exit: kfree(full_path); FreeXid(xid); -- cgit v1.2.3 From 67750fb9e07940c078d1edb16fd736ccc92a4a4e Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 9 May 2008 22:28:02 +0000 Subject: [CIFS] when not using unix extensions, check for and set ATTR_READONLY on create and mkdir When creating a directory on a CIFS share without POSIX extensions, and the given mode has no write bits set, set the ATTR_READONLY bit. When creating a file, set ATTR_READONLY if the create mode has no write bits set and we're not using unix extensions. There are some comments about this being problematic due to the VFS splitting creates into 2 parts. I'm not sure what that's actually talking about, but I'm assuming that it has something to do with how mknod is implemented. In the simple case where we have no unix extensions and we're just creating a regular file, there's no reason we can't set ATTR_READONLY. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifspdu.h | 1 + fs/cifs/cifssmb.c | 16 ++++++---------- fs/cifs/dir.c | 16 +++++++++++++--- fs/cifs/inode.c | 15 +++++++++++---- 4 files changed, 31 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index a0d26b540d4..c43bf4b7a55 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -340,6 +340,7 @@ #define OPEN_NO_RECALL 0x00400000 #define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */ #define CREATE_OPTIONS_MASK 0x007FFFFF +#define CREATE_OPTION_READONLY 0x10000000 #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ /* ImpersonationLevel flags */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index cfd9750852b..95fbba4ea7d 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1224,11 +1224,8 @@ OldOpenRetry: else /* BB FIXME BB */ pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); - /* if ((omode & S_IWUGO) == 0) - pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ - /* Above line causes problems due to vfs splitting create into two - pieces - need to set mode after file created not while it is - being created */ + if (create_options & CREATE_OPTION_READONLY) + pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY); /* BB FIXME BB */ /* pSMB->CreateOptions = cpu_to_le32(create_options & @@ -1331,17 +1328,16 @@ openRetry: pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); else pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); + /* XP does not handle ATTR_POSIX_SEMANTICS */ /* but it helps speed up case sensitive checks for other servers such as Samba */ if (tcon->ses->capabilities & CAP_UNIX) pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); - /* if ((omode & S_IWUGO) == 0) - pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ - /* Above line causes problems due to vfs splitting create into two - pieces - need to set mode after file created not while it is - being created */ + if (create_options & CREATE_OPTION_READONLY) + pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY); + pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); pSMB->CreateDisposition = cpu_to_le32(openDisposition); pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 6ed775986be..e4e0078a052 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -119,6 +119,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, { int rc = -ENOENT; int xid; + int create_options = CREATE_NOT_DIR; int oplock = 0; int desiredAccess = GENERIC_READ | GENERIC_WRITE; __u16 fileHandle; @@ -176,9 +177,19 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, FreeXid(xid); return -ENOMEM; } + + mode &= ~current->fs->umask; + + /* + * if we're not using unix extensions, see if we need to set + * ATTR_READONLY on the create call + */ + if (!pTcon->unix_ext && (mode & S_IWUGO) == 0) + create_options |= CREATE_OPTION_READONLY; + if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, - desiredAccess, CREATE_NOT_DIR, + desiredAccess, create_options, &fileHandle, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); else @@ -187,7 +198,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, if (rc == -EIO) { /* old server, retry the open legacy style */ rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, - desiredAccess, CREATE_NOT_DIR, + desiredAccess, create_options, &fileHandle, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } @@ -197,7 +208,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, /* If Open reported that we actually created a file then we now have to set the mode if possible */ if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { - mode &= ~current->fs->umask; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)current->fsuid, diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index d904a037c83..fcbdbb6ad7b 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -974,8 +974,8 @@ mkdir_get_info: * failed to get it from the server or was set bogus */ if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) direntry->d_inode->i_nlink = 2; + mode &= ~current->fs->umask; if (pTcon->unix_ext) { - mode &= ~current->fs->umask; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, @@ -994,9 +994,16 @@ mkdir_get_info: CIFS_MOUNT_MAP_SPECIAL_CHR); } } else { - /* BB to be implemented via Windows secrty descriptors - eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, - -1, -1, local_nls); */ + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && + (mode & S_IWUGO) == 0) { + FILE_BASIC_INFO pInfo; + memset(&pInfo, 0, sizeof(pInfo)); + pInfo.Attributes = cpu_to_le32(ATTR_READONLY); + CIFSSMBSetTimes(xid, pTcon, full_path, + &pInfo, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + } if (direntry->d_inode) { direntry->d_inode->i_mode = mode; direntry->d_inode->i_mode |= S_IFDIR; -- cgit v1.2.3 From e691b9d1a096fbaaff9d6d6aef1adc593b786e62 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 11 May 2008 15:53:33 +0000 Subject: [CIFS] don't allow demultiplex thread to exit until kthread_stop is called cifs_demultiplex_thread can exit under several conditions: 1) if it's signaled 2) if there's a problem with session setup 3) if kthread_stop is called on it The first two are problems. If kthread_stop is called on the thread, there is no guarantee that it will still be up. We need to have the thread stay up until kthread_stop is called on it. One option would be to not even try to tear things down until after kthread_stop is called. However, in the case where there is a problem setting up the session, there's no real reason to try continuing the loop. This patch allows the thread to clean up and prepare for exit under all three conditions, but it has the thread go to sleep until kthread_stop is called. This allows us to simplify the shutdown code somewhat since we can be reasonably sure that the thread won't exit after being signaled but before kthread_stop is called. It also removes the places where the thread itself set the tsk variable since it appeared that it could have a potential race where the thread might never be shut down. Signed-off-by: Jeff Layton Acked-by: Christoph Hellwig Signed-off-by: Steve French --- fs/cifs/connect.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 96505086759..f428bf3bf1a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -348,7 +348,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) int reconnect; current->flags |= PF_MEMALLOC; - server->tsk = current; /* save process info to wake at shutdown */ cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current))); write_lock(&GlobalSMBSeslock); atomic_inc(&tcpSesAllocCount); @@ -651,10 +650,20 @@ multi_t2_fnd: spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; - server->tsk = NULL; + spin_unlock(&GlobalMid_Lock); + + /* don't exit until kthread_stop is called */ + set_current_state(TASK_UNINTERRUPTIBLE); + while (!kthread_should_stop()) { + schedule(); + set_current_state(TASK_UNINTERRUPTIBLE); + } + set_current_state(TASK_RUNNING); + /* check if we have blocked requests that need to free */ /* Note that cifs_max_pending is normally 50, but can be set at module install time to as little as two */ + spin_lock(&GlobalMid_Lock); if (atomic_read(&server->inFlight) >= cifs_max_pending) atomic_set(&server->inFlight, cifs_max_pending - 1); /* We do not want to set the max_pending too low or we @@ -2187,15 +2196,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, srvTcp->tcpStatus = CifsExiting; spin_unlock(&GlobalMid_Lock); if (srvTcp->tsk) { - struct task_struct *tsk; /* If we could verify that kthread_stop would always wake up processes blocked in tcp in recv_mesg then we could remove the send_sig call */ force_sig(SIGKILL, srvTcp->tsk); - tsk = srvTcp->tsk; - if (tsk) - kthread_stop(tsk); + kthread_stop(srvTcp->tsk); } } /* If find_unc succeeded then rc == 0 so we can not end */ @@ -2211,23 +2217,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if ((temp_rc == -ESHUTDOWN) && (pSesInfo->server) && (pSesInfo->server->tsk)) { - struct task_struct *tsk; force_sig(SIGKILL, pSesInfo->server->tsk); - tsk = pSesInfo->server->tsk; - if (tsk) - kthread_stop(tsk); + kthread_stop(pSesInfo->server->tsk); } } else { cFYI(1, ("No session or bad tcon")); if ((pSesInfo->server) && (pSesInfo->server->tsk)) { - struct task_struct *tsk; force_sig(SIGKILL, pSesInfo->server->tsk); - tsk = pSesInfo->server->tsk; - if (tsk) - kthread_stop(tsk); + kthread_stop(pSesInfo->server->tsk); } } sesInfoFree(pSesInfo); -- cgit v1.2.3 From 091806edd458486af13ad83c9802f5b8b54d6d19 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 29 Apr 2008 12:35:48 -0500 Subject: [GFS2] filesystem consistency error from do_strip This patch fixes a GFS2 filesystem consistency error reported from function do_strip. The problem was caused by a timing window that allowed two vfs inodes to be created in memory that point to the same file. The problem is fixed by making the vfs's iget_test, iget_set mechanism check and set a new bit in the in-core gfs2_inode structure while the vfs inode spin_lock is held. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/glops.c | 2 +- fs/gfs2/incore.h | 1 + fs/gfs2/inode.c | 10 +++++----- fs/gfs2/meta_io.c | 6 ++++-- fs/gfs2/ops_super.c | 16 +++++++++------- 5 files changed, 20 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index d31badadef8..07d84d16cda 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -249,7 +249,7 @@ static int inode_go_lock(struct gfs2_holder *gh) struct gfs2_inode *ip = gl->gl_object; int error = 0; - if (!ip) + if (!ip || (gh->gh_flags & GL_SKIP)) return 0; if (test_bit(GIF_INVALID, &ip->i_flags)) { diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 9c2c0b90b22..eabe5eac41d 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -236,6 +236,7 @@ enum { GIF_INVALID = 0, GIF_QD_LOCKED = 1, GIF_SW_PAGED = 3, + GIF_USER = 4, /* user inode, not metadata addr space */ }; struct gfs2_dinode_host { diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 3a9ef526c30..09453d057e4 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -47,8 +47,7 @@ static int iget_test(struct inode *inode, void *opaque) struct gfs2_inode *ip = GFS2_I(inode); u64 *no_addr = opaque; - if (ip->i_no_addr == *no_addr && - inode->i_private != NULL) + if (ip->i_no_addr == *no_addr && test_bit(GIF_USER, &ip->i_flags)) return 1; return 0; @@ -61,6 +60,7 @@ static int iget_set(struct inode *inode, void *opaque) inode->i_ino = (unsigned long)*no_addr; ip->i_no_addr = *no_addr; + set_bit(GIF_USER, &ip->i_flags); return 0; } @@ -86,7 +86,7 @@ static int iget_skip_test(struct inode *inode, void *opaque) struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_skip_data *data = opaque; - if (ip->i_no_addr == data->no_addr && inode->i_private != NULL){ + if (ip->i_no_addr == data->no_addr && test_bit(GIF_USER, &ip->i_flags)){ if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){ data->skipped = 1; return 0; @@ -105,6 +105,7 @@ static int iget_skip_set(struct inode *inode, void *opaque) return 1; inode->i_ino = (unsigned long)(data->no_addr); ip->i_no_addr = data->no_addr; + set_bit(GIF_USER, &ip->i_flags); return 0; } @@ -166,7 +167,7 @@ void gfs2_set_iop(struct inode *inode) * Returns: A VFS inode, or an error */ -struct inode *gfs2_inode_lookup(struct super_block *sb, +struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, u64 no_addr, u64 no_formal_ino, int skip_freeing) @@ -187,7 +188,6 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, if (inode->i_state & I_NEW) { struct gfs2_sbd *sdp = GFS2_SB(inode); - inode->i_private = ip; ip->i_no_formal_ino = no_formal_ino; error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 85aea27b4a8..78d75f892f8 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -69,13 +69,15 @@ static const struct address_space_operations aspace_aops = { struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp) { struct inode *aspace; + struct gfs2_inode *ip; aspace = new_inode(sdp->sd_vfs); if (aspace) { mapping_set_gfp_mask(aspace->i_mapping, GFP_NOFS); aspace->i_mapping->a_ops = &aspace_aops; aspace->i_size = ~0ULL; - aspace->i_private = NULL; + ip = GFS2_I(aspace); + clear_bit(GIF_USER, &ip->i_flags); insert_inode_hash(aspace); } return aspace; diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 2278c68b7e3..0b7cc920eb8 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -52,7 +52,7 @@ static int gfs2_write_inode(struct inode *inode, int sync) struct gfs2_inode *ip = GFS2_I(inode); /* Check this is a "normal" inode */ - if (inode->i_private) { + if (test_bit(GIF_USER, &ip->i_flags)) { if (current->flags & PF_MEMALLOC) return 0; if (sync) @@ -297,8 +297,9 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) */ static void gfs2_drop_inode(struct inode *inode) { - if (inode->i_private && inode->i_nlink) { - struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_inode *ip = GFS2_I(inode); + + if (test_bit(GIF_USER, &ip->i_flags) && inode->i_nlink) { struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl; if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags)) clear_nlink(inode); @@ -314,12 +315,13 @@ static void gfs2_drop_inode(struct inode *inode) static void gfs2_clear_inode(struct inode *inode) { + struct gfs2_inode *ip = GFS2_I(inode); + /* This tells us its a "real" inode and not one which only * serves to contain an address space (see rgrp.c, meta_io.c) * which therefore doesn't have its own glocks. */ - if (inode->i_private) { - struct gfs2_inode *ip = GFS2_I(inode); + if (test_bit(GIF_USER, &ip->i_flags)) { ip->i_gl->gl_object = NULL; gfs2_glock_schedule_for_reclaim(ip->i_gl); gfs2_glock_put(ip->i_gl); @@ -419,7 +421,7 @@ static void gfs2_delete_inode(struct inode *inode) struct gfs2_holder gh; int error; - if (!inode->i_private) + if (!test_bit(GIF_USER, &ip->i_flags)) goto out; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); -- cgit v1.2.3 From ad99f77778e83358c371dab7a50bde69270ed6b8 Mon Sep 17 00:00:00 2001 From: Andrew Price Date: Thu, 1 May 2008 11:55:38 +0100 Subject: [GFS2] Fix cast from unsigned int to s64 This fixes bz 444829 where allocating a new block caused gfs2 file systems to report 0 bytes used in df. It was caused by a broken cast from an unsigned int in gfs2_block_alloc() to a negative s64 in gfs2_statfs_change(). This patch casts the unsigned int to an s64 before the unary minus is applied. Signed-off-by: Andrew Price Signed-off-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 7e8f0b1d6c6..6387523a315 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1495,7 +1495,7 @@ u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n) al->al_alloced += *n; - gfs2_statfs_change(sdp, 0, -*n, 0); + gfs2_statfs_change(sdp, 0, -(s64)*n, 0); gfs2_quota_change(ip, *n, ip->i_inode.i_uid, ip->i_inode.i_gid); spin_lock(&sdp->sd_rindex_spin); -- cgit v1.2.3 From 00377d8e3842776d1da633ad9c79a16ecb548b92 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 9 May 2008 17:59:51 +0200 Subject: [GFS2] Prefer strlcpy() over snprintf() strlcpy is faster than snprintf when you don't use the returned value. Signed-off-by: Jean Delvare Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index ef9c6c4f80f..b2028c82e8d 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -142,8 +142,8 @@ static int init_names(struct gfs2_sbd *sdp, int silent) if (!table[0]) table = sdp->sd_vfs->s_id; - snprintf(sdp->sd_proto_name, GFS2_FSNAME_LEN, "%s", proto); - snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table); + strlcpy(sdp->sd_proto_name, proto, GFS2_FSNAME_LEN); + strlcpy(sdp->sd_table_name, table, GFS2_FSNAME_LEN); table = sdp->sd_table_name; while ((table = strchr(table, '/'))) -- cgit v1.2.3 From d0a9c078db4769f7305ff9774558776d12bfb25b Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 May 2008 22:23:49 +0000 Subject: [CIFS] CIFS currently allows for permissions to be changed on files, even when unix extensions and cifsacl support are disabled. These permissions changes are "ephemeral" however. They are lost whenever a share is mounted and unmounted, or when memory pressure forces the inode out of the cache. Because of this, we'd like to introduce a behavior change to make CIFS behave more like local DOS/Windows filesystems. When unix extensions and cifsacl support aren't enabled, then don't silently ignore changes to permission bits that can't be reflected on the server. Still, there may be people relying on the current behavior for certain applications. This patch adds a new "dynperm" (and a corresponding "nodynperm") mount option that will be intended to make the client fall back to legacy behavior when setting these modes. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 1 + fs/cifs/connect.c | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'fs') diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 8ad2330ba06..877c85409f1 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -30,6 +30,7 @@ #define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */ #define CIFS_MOUNT_OVERR_UID 0x400 /* override uid returned from server */ #define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */ +#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f428bf3bf1a..8e2fa6d46c7 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -75,6 +75,7 @@ struct smb_vol { bool setuids:1; bool override_uid:1; bool override_gid:1; + bool dynperm:1; bool noperm:1; bool no_psx_acl:1; /* set if posix acl support should be disabled */ bool cifs_acl:1; @@ -1246,6 +1247,10 @@ cifs_parse_mount_options(char *options, const char *devname, vol->setuids = 1; } else if (strnicmp(data, "nosetuids", 9) == 0) { vol->setuids = 0; + } else if (strnicmp(data, "dynperm", 7) == 0) { + vol->dynperm = true; + } else if (strnicmp(data, "nodynperm", 9) == 0) { + vol->dynperm = false; } else if (strnicmp(data, "nohard", 6) == 0) { vol->retry = 0; } else if (strnicmp(data, "nosoft", 6) == 0) { @@ -2125,6 +2130,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; if (volume_info.override_gid) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; + if (volume_info.dynperm) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; if (volume_info.direct_io) { cFYI(1, ("mounting share using direct i/o")); cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; -- cgit v1.2.3 From 6353450a2deefaa79cdb4fd2b72830c7db610256 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 May 2008 19:56:05 -0700 Subject: fix memory leak in CIFSFindNext When CIFSFindNext gets back an -EBADF from a call, it sets the return code of the function to 0 and eventually exits. Doing this makes the cleanup at the end of the function skip freeing the SMB buffer, so we need to make sure we free the buffer explicitly when doing this. If we don't you end up with errors like this when unplugging the cifs kernel module: slab error in kmem_cache_destroy(): cache `cifs_request': Can't free all objects [] kmem_cache_destroy+0x61/0xf3 [] cifs_destroy_request_bufs+0x14/0x28 [cifs] [] exit_cifs+0x1e/0x80 [cifs] [] sys_delete_module+0x192/0x1b8 [] audit_syscall_entry+0x14b/0x17d [] syscall_call+0x7/0xb ======================= Signed-off-by: Jeff Layton --- fs/cifs/CHANGES | 3 ++- fs/cifs/cifssmb.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 8355e918fdd..502a4c2b841 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -12,7 +12,8 @@ Add ability to modify cifs acls for handling chmod (when mounted with cifsacl flag). Fix prefixpath path separator so we can handle mounts with prefixpaths longer than one directory (one path component) when mounted to Windows servers. Fix slow file open when cifsacl -enabled. +enabled. Fix memory leak in FindNext when the SMB call returns -EBADF. + Version 1.51 ------------ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 95fbba4ea7d..641cc8ffc51 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3679,6 +3679,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, if (rc) { if (rc == -EBADF) { psrch_inf->endOfSearch = true; + cifs_buf_release(pSMB); rc = 0; /* search probably was closed at end of search*/ } else cFYI(1, ("FindNext returned = %d", rc)); -- cgit v1.2.3 From ed5f037005d728de19a0f63678ac35b42064966d Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Tue, 13 May 2008 04:01:01 +0000 Subject: [CIFS] CIFSSMBPosixLock should return -EINVAL on error all other codepaths in this function return negative values on errors Signed-off-by: Marcin Slusarz Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 641cc8ffc51..1cbe61524ef 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1767,7 +1767,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, cFYI(1, ("Posix Lock")); if (pLockData == NULL) - return EINVAL; + return -EINVAL; rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); -- cgit v1.2.3 From 582d21e5e319d38c0485d8b9e92f6f2341f7c79b Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 13 May 2008 04:54:12 +0000 Subject: [CIFS] cleanup old checkpatch warnings Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 6 +++--- fs/cifs/cifssmb.c | 51 +++++++++++++++++++++++++++++++++------------------ fs/cifs/connect.c | 7 ++++--- fs/cifs/netmisc.c | 6 +++--- fs/cifs/ntlmssp.h | 4 ++-- 5 files changed, 45 insertions(+), 29 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index d481f6c5a2b..08248e85b78 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -93,7 +93,7 @@ extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time); extern int cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, - FILE_ALL_INFO * pfile_info, + FILE_ALL_INFO *pfile_info, struct super_block *sb, int xid, const __u16 *pfid); extern int cifs_get_inode_info_unix(struct inode **pinode, const unsigned char *search_path, @@ -130,7 +130,7 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, - FILE_ALL_INFO * findData, + FILE_ALL_INFO *findData, int legacy /* whether to use old info level */, const struct nls_table *nls_codepage, int remap); extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, @@ -141,7 +141,7 @@ extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, - FILE_UNIX_BASIC_INFO * pFindData, + FILE_UNIX_BASIC_INFO *pFindData, const struct nls_table *nls_codepage, int remap); extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 1cbe61524ef..3c05c2de50e 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1247,7 +1247,7 @@ OldOpenRetry: } else { /* BB verify if wct == 15 */ -/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */ +/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/ *netfid = pSMBr->Fid; /* cifs fid stays in le */ /* Let caller know file was created so we can set the mode. */ @@ -1944,7 +1944,7 @@ renameRetry: /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; name_len2 = - cifsConvertToUCS((__le16 *) &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 */ @@ -2925,7 +2925,8 @@ setAclRetry: } params = 6 + name_len; pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ + /* BB find max SMB size from sess */ + pSMB->MaxDataCount = cpu_to_le16(1000); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -3322,7 +3323,8 @@ QPathInfoRetry: params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(4000); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -3388,7 +3390,7 @@ QPathInfoRetry: int CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, - FILE_UNIX_BASIC_INFO * pFindData, + FILE_UNIX_BASIC_INFO *pFindData, const struct nls_table *nls_codepage, int remap) { /* SMB_QUERY_FILE_UNIX_BASIC */ @@ -3922,7 +3924,8 @@ getDFSRetry: pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->MaxParameterCount = 0; - pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(4000); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -4230,7 +4233,8 @@ QFSAttributeRetry: params = 2; /* level */ pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(1000); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -4299,7 +4303,8 @@ QFSDeviceRetry: params = 2; /* level */ pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(1000); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -4370,7 +4375,8 @@ QFSUnixRetry: pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(100); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -4445,7 +4451,8 @@ SETFSUnixRetry: offset = param_offset + params; pSMB->MaxParameterCount = cpu_to_le16(4); - pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(100); pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); @@ -4513,7 +4520,8 @@ QFSPosixRetry: pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(100); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -4703,7 +4711,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, count = sizeof(struct file_end_of_file_info); pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(1000); pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); @@ -4790,7 +4799,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, count = sizeof(FILE_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ + /* BB find max SMB PDU from sess */ + pSMB->MaxDataCount = cpu_to_le16(1000); pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); @@ -4857,7 +4867,8 @@ SetTimesRetry: params = 6 + name_len; count = sizeof(FILE_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + /* BB find max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(1000); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -4987,7 +4998,8 @@ setPermsRetry: params = 6 + name_len; count = sizeof(FILE_UNIX_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + /* BB find max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(1000); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -5170,7 +5182,8 @@ QAllEAsRetry: params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(4000); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -5318,7 +5331,8 @@ QEARetry: params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(4000); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -5476,7 +5490,8 @@ SetEARetry: count = sizeof(*parm_data) + ea_value_len + name_len; pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ + /* BB find max SMB PDU from sess */ + pSMB->MaxDataCount = cpu_to_le16(1000); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8e2fa6d46c7..7c2e5ea0330 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1820,7 +1820,7 @@ convert_delimiter(char *path, char delim) if (path == NULL) return; - if (delim == '/') + if (delim == '/') old_delim = '\\'; else old_delim = '/'; @@ -2321,9 +2321,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, user = ses->userName; domain = ses->domainName; smb_buffer = cifs_buf_get(); - if (smb_buffer == NULL) { + + if (smb_buffer == NULL) return -ENOMEM; - } + smb_buffer_response = smb_buffer; pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 00f4cff400b..8703d68f5b2 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -141,11 +141,11 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst) int ret = 0; /* calculate length by finding first slash or NULL */ - if (address_family == AF_INET) { + if (address_family == AF_INET) ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL); - } else if (address_family == AF_INET6) { + else if (address_family == AF_INET6) ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL); - } + cFYI(DBG2, ("address conversion returned %d for %s", ret, cp)); if (ret > 0) ret = 1; diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 7170a9b70f1..c377d8065d9 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h @@ -64,7 +64,7 @@ typedef struct _SECURITY_BUFFER { } __attribute__((packed)) SECURITY_BUFFER; typedef struct _NEGOTIATE_MESSAGE { - __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; + __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; __le32 MessageType; /* 1 */ __le32 NegotiateFlags; SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ @@ -74,7 +74,7 @@ typedef struct _NEGOTIATE_MESSAGE { } __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; typedef struct _CHALLENGE_MESSAGE { - __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; + __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; __le32 MessageType; /* 2 */ SECURITY_BUFFER TargetName; __le32 NegotiateFlags; -- cgit v1.2.3 From a0612b1f0b3d851458dafe5886e33d58c1967440 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 12 May 2008 14:01:49 -0700 Subject: uml: hppfs fixes hppfs tidying and fixes noticed during hch's get_inode work - style fixes a copy_to_user got its return value checked hppfs_write no longer fiddles file->f_pos because it gets and returns pos in its arguments hppfs_delete_inode dputs the underlyng procfs dentry stored in its private data and mntputs the vfsmnt stashed in s_fs_info hppfs_put_super no longer needs to mntput the s_fs_info, so it no longer needs to exist hppfs_readlink and hppfs_follow_link were doing a bunch of stuff with a struct file which they didn't use there is now a ->permission which calls generic_permission get_inode was always returning 0 for some reason - it now returns an inode if nothing bad happened Signed-off-by: Jeff Dike Cc: WANG Cong Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hppfs/hppfs_kern.c | 82 +++++++++++++++++++-------------------------------- 1 file changed, 30 insertions(+), 52 deletions(-) (limited to 'fs') diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c index 8601d8ef3b5..65077aa90f0 100644 --- a/fs/hppfs/hppfs_kern.c +++ b/fs/hppfs/hppfs_kern.c @@ -33,7 +33,7 @@ struct hppfs_private { }; struct hppfs_inode_info { - struct dentry *proc_dentry; + struct dentry *proc_dentry; struct inode vfs_inode; }; @@ -52,7 +52,7 @@ static int is_pid(struct dentry *dentry) int i; sb = dentry->d_sb; - if ((sb->s_op != &hppfs_sbops) || (dentry->d_parent != sb->s_root)) + if (dentry->d_parent != sb->s_root) return 0; for (i = 0; i < dentry->d_name.len; i++) { @@ -136,7 +136,7 @@ static int file_removed(struct dentry *dentry, const char *file) } static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, - struct nameidata *nd) + struct nameidata *nd) { struct dentry *proc_dentry, *new, *parent; struct inode *inode; @@ -254,6 +254,8 @@ static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count, int err; if (hppfs->contents != NULL) { + int rem; + if (*ppos >= hppfs->len) return 0; @@ -267,8 +269,10 @@ static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count, if (off + count > hppfs->len) count = hppfs->len - off; - copy_to_user(buf, &data->contents[off], count); - *ppos += count; + rem = copy_to_user(buf, &data->contents[off], count); + *ppos += count - rem; + if (rem > 0) + return -EFAULT; } else if (hppfs->host_fd != -1) { err = os_seek_file(hppfs->host_fd, *ppos); if (err) { @@ -285,21 +289,15 @@ static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count, return count; } -static ssize_t hppfs_write(struct file *file, const char __user *buf, size_t len, - loff_t *ppos) +static ssize_t hppfs_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) { struct hppfs_private *data = file->private_data; struct file *proc_file = data->proc_file; ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); - int err; write = proc_file->f_path.dentry->d_inode->i_fop->write; - - proc_file->f_pos = file->f_pos; - err = (*write)(proc_file, buf, len, &proc_file->f_pos); - file->f_pos = proc_file->f_pos; - - return err; + return (*write)(proc_file, buf, len, ppos); } static int open_host_sock(char *host_file, int *filter_out) @@ -357,7 +355,7 @@ static struct hppfs_data *hppfs_get_data(int fd, int filter, if (filter) { while ((n = read_proc(proc_file, data->contents, - sizeof(data->contents), NULL, 0)) > 0) + sizeof(data->contents), NULL, 0)) > 0) os_write_file(fd, data->contents, n); err = os_shutdown_socket(fd, 0, 1); if (err) { @@ -429,8 +427,8 @@ static int file_mode(int fmode) static int hppfs_open(struct inode *inode, struct file *file) { struct hppfs_private *data; - struct dentry *proc_dentry; struct vfsmount *proc_mnt; + struct dentry *proc_dentry; char *host_file; int err, fd, type, filter; @@ -492,8 +490,8 @@ static int hppfs_open(struct inode *inode, struct file *file) static int hppfs_dir_open(struct inode *inode, struct file *file) { struct hppfs_private *data; - struct dentry *proc_dentry; struct vfsmount *proc_mnt; + struct dentry *proc_dentry; int err; err = -ENOMEM; @@ -620,6 +618,9 @@ static struct inode *hppfs_alloc_inode(struct super_block *sb) void hppfs_delete_inode(struct inode *ino) { + dput(HPPFS_I(ino)->proc_dentry); + mntput(ino->i_sb->s_fs_info); + clear_inode(ino); } @@ -628,69 +629,46 @@ static void hppfs_destroy_inode(struct inode *inode) kfree(HPPFS_I(inode)); } -static void hppfs_put_super(struct super_block *sb) -{ - mntput(sb->s_fs_info); -} - static const struct super_operations hppfs_sbops = { .alloc_inode = hppfs_alloc_inode, .destroy_inode = hppfs_destroy_inode, .delete_inode = hppfs_delete_inode, .statfs = hppfs_statfs, - .put_super = hppfs_put_super, }; static int hppfs_readlink(struct dentry *dentry, char __user *buffer, int buflen) { - struct file *proc_file; struct dentry *proc_dentry; - struct vfsmount *proc_mnt; - int ret; proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; - proc_mnt = dentry->d_sb->s_fs_info; - - proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), O_RDONLY); - if (IS_ERR(proc_file)) - return PTR_ERR(proc_file); - - ret = proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer, buflen); - - fput(proc_file); - - return ret; + return proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer, + buflen); } -static void* hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct file *proc_file; struct dentry *proc_dentry; - struct vfsmount *proc_mnt; - void *ret; proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; - proc_mnt = dentry->d_sb->s_fs_info; - - proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), O_RDONLY); - if (IS_ERR(proc_file)) - return proc_file; - - ret = proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd); - fput(proc_file); + return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd); +} - return ret; +int hppfs_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + return generic_permission(inode, mask, NULL); } static const struct inode_operations hppfs_dir_iops = { .lookup = hppfs_lookup, + .permission = hppfs_permission, }; static const struct inode_operations hppfs_link_iops = { .readlink = hppfs_readlink, .follow_link = hppfs_follow_link, + .permission = hppfs_permission, }; static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) @@ -712,7 +690,7 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) inode->i_fop = &hppfs_file_fops; } - HPPFS_I(inode)->proc_dentry = dentry; + HPPFS_I(inode)->proc_dentry = dget(dentry); inode->i_uid = proc_ino->i_uid; inode->i_gid = proc_ino->i_gid; @@ -725,7 +703,7 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) inode->i_size = proc_ino->i_size; inode->i_blocks = proc_ino->i_blocks; - return 0; + return inode; } static int hppfs_fill_super(struct super_block *sb, void *d, int silent) -- cgit v1.2.3 From 46d7b522ebf486edbd096965d534cc6465e9e309 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 12 May 2008 14:01:50 -0700 Subject: uml: move hppfs_kern.c to hppfs.c There's no reason for the _kern in hppfs_kern.c, so move it to hppfs.c. Signed-off-by: Jeff Dike Cc: WANG Cong Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hppfs/Makefile | 6 +- fs/hppfs/hppfs.c | 771 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/hppfs/hppfs_kern.c | 771 -------------------------------------------------- 3 files changed, 774 insertions(+), 774 deletions(-) create mode 100644 fs/hppfs/hppfs.c delete mode 100644 fs/hppfs/hppfs_kern.c (limited to 'fs') diff --git a/fs/hppfs/Makefile b/fs/hppfs/Makefile index 6890433f759..8a1f5034436 100644 --- a/fs/hppfs/Makefile +++ b/fs/hppfs/Makefile @@ -1,9 +1,9 @@ # -# Copyright (C) 2002, 2003 Jeff Dike (jdike@karaya.com) +# Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) # Licensed under the GPL # -hppfs-objs := hppfs_kern.o +hppfs-objs := hppfs.o obj-y = -obj-$(CONFIG_HPPFS) += hppfs.o +obj-$(CONFIG_HPPFS) += $(hppfs-objs) diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c new file mode 100644 index 00000000000..65077aa90f0 --- /dev/null +++ b/fs/hppfs/hppfs.c @@ -0,0 +1,771 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "os.h" + +static struct inode *get_inode(struct super_block *, struct dentry *); + +struct hppfs_data { + struct list_head list; + char contents[PAGE_SIZE - sizeof(struct list_head)]; +}; + +struct hppfs_private { + struct file *proc_file; + int host_fd; + loff_t len; + struct hppfs_data *contents; +}; + +struct hppfs_inode_info { + struct dentry *proc_dentry; + struct inode vfs_inode; +}; + +static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode) +{ + return container_of(inode, struct hppfs_inode_info, vfs_inode); +} + +#define HPPFS_SUPER_MAGIC 0xb00000ee + +static const struct super_operations hppfs_sbops; + +static int is_pid(struct dentry *dentry) +{ + struct super_block *sb; + int i; + + sb = dentry->d_sb; + if (dentry->d_parent != sb->s_root) + return 0; + + for (i = 0; i < dentry->d_name.len; i++) { + if (!isdigit(dentry->d_name.name[i])) + return 0; + } + return 1; +} + +static char *dentry_name(struct dentry *dentry, int extra) +{ + struct dentry *parent; + char *root, *name; + const char *seg_name; + int len, seg_len; + + len = 0; + parent = dentry; + while (parent->d_parent != parent) { + if (is_pid(parent)) + len += strlen("pid") + 1; + else len += parent->d_name.len + 1; + parent = parent->d_parent; + } + + root = "proc"; + len += strlen(root); + name = kmalloc(len + extra + 1, GFP_KERNEL); + if (name == NULL) + return NULL; + + name[len] = '\0'; + parent = dentry; + while (parent->d_parent != parent) { + if (is_pid(parent)) { + seg_name = "pid"; + seg_len = strlen("pid"); + } + else { + seg_name = parent->d_name.name; + seg_len = parent->d_name.len; + } + + len -= seg_len + 1; + name[len] = '/'; + strncpy(&name[len + 1], seg_name, seg_len); + parent = parent->d_parent; + } + strncpy(name, root, strlen(root)); + return name; +} + +static int file_removed(struct dentry *dentry, const char *file) +{ + char *host_file; + int extra, fd; + + extra = 0; + if (file != NULL) + extra += strlen(file) + 1; + + host_file = dentry_name(dentry, extra + strlen("/remove")); + if (host_file == NULL) { + printk(KERN_ERR "file_removed : allocation failed\n"); + return -ENOMEM; + } + + if (file != NULL) { + strcat(host_file, "/"); + strcat(host_file, file); + } + strcat(host_file, "/remove"); + + fd = os_open_file(host_file, of_read(OPENFLAGS()), 0); + kfree(host_file); + if (fd > 0) { + os_close_file(fd); + return 1; + } + return 0; +} + +static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, + struct nameidata *nd) +{ + struct dentry *proc_dentry, *new, *parent; + struct inode *inode; + int err, deleted; + + deleted = file_removed(dentry, NULL); + if (deleted < 0) + return ERR_PTR(deleted); + else if (deleted) + return ERR_PTR(-ENOENT); + + err = -ENOMEM; + parent = HPPFS_I(ino)->proc_dentry; + mutex_lock(&parent->d_inode->i_mutex); + proc_dentry = d_lookup(parent, &dentry->d_name); + if (proc_dentry == NULL) { + proc_dentry = d_alloc(parent, &dentry->d_name); + if (proc_dentry == NULL) { + mutex_unlock(&parent->d_inode->i_mutex); + goto out; + } + new = (*parent->d_inode->i_op->lookup)(parent->d_inode, + proc_dentry, NULL); + if (new) { + dput(proc_dentry); + proc_dentry = new; + } + } + mutex_unlock(&parent->d_inode->i_mutex); + + if (IS_ERR(proc_dentry)) + return proc_dentry; + + err = -ENOMEM; + inode = get_inode(ino->i_sb, proc_dentry); + if (!inode) + goto out_dput; + + d_add(dentry, inode); + return NULL; + + out_dput: + dput(proc_dentry); + out: + return ERR_PTR(err); +} + +static const struct inode_operations hppfs_file_iops = { +}; + +static ssize_t read_proc(struct file *file, char __user *buf, ssize_t count, + loff_t *ppos, int is_user) +{ + ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); + ssize_t n; + + read = file->f_path.dentry->d_inode->i_fop->read; + + if (!is_user) + set_fs(KERNEL_DS); + + n = (*read)(file, buf, count, &file->f_pos); + + if (!is_user) + set_fs(USER_DS); + + if (ppos) + *ppos = file->f_pos; + return n; +} + +static ssize_t hppfs_read_file(int fd, char __user *buf, ssize_t count) +{ + ssize_t n; + int cur, err; + char *new_buf; + + n = -ENOMEM; + new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (new_buf == NULL) { + printk(KERN_ERR "hppfs_read_file : kmalloc failed\n"); + goto out; + } + n = 0; + while (count > 0) { + cur = min_t(ssize_t, count, PAGE_SIZE); + err = os_read_file(fd, new_buf, cur); + if (err < 0) { + printk(KERN_ERR "hppfs_read : read failed, " + "errno = %d\n", err); + n = err; + goto out_free; + } else if (err == 0) + break; + + if (copy_to_user(buf, new_buf, err)) { + n = -EFAULT; + goto out_free; + } + n += err; + count -= err; + } + out_free: + kfree(new_buf); + out: + return n; +} + +static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + struct hppfs_private *hppfs = file->private_data; + struct hppfs_data *data; + loff_t off; + int err; + + if (hppfs->contents != NULL) { + int rem; + + if (*ppos >= hppfs->len) + return 0; + + data = hppfs->contents; + off = *ppos; + while (off >= sizeof(data->contents)) { + data = list_entry(data->list.next, struct hppfs_data, + list); + off -= sizeof(data->contents); + } + + if (off + count > hppfs->len) + count = hppfs->len - off; + rem = copy_to_user(buf, &data->contents[off], count); + *ppos += count - rem; + if (rem > 0) + return -EFAULT; + } else if (hppfs->host_fd != -1) { + err = os_seek_file(hppfs->host_fd, *ppos); + if (err) { + printk(KERN_ERR "hppfs_read : seek failed, " + "errno = %d\n", err); + return err; + } + count = hppfs_read_file(hppfs->host_fd, buf, count); + if (count > 0) + *ppos += count; + } + else count = read_proc(hppfs->proc_file, buf, count, ppos, 1); + + return count; +} + +static ssize_t hppfs_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct hppfs_private *data = file->private_data; + struct file *proc_file = data->proc_file; + ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); + + write = proc_file->f_path.dentry->d_inode->i_fop->write; + return (*write)(proc_file, buf, len, ppos); +} + +static int open_host_sock(char *host_file, int *filter_out) +{ + char *end; + int fd; + + end = &host_file[strlen(host_file)]; + strcpy(end, "/rw"); + *filter_out = 1; + fd = os_connect_socket(host_file); + if (fd > 0) + return fd; + + strcpy(end, "/r"); + *filter_out = 0; + fd = os_connect_socket(host_file); + return fd; +} + +static void free_contents(struct hppfs_data *head) +{ + struct hppfs_data *data; + struct list_head *ele, *next; + + if (head == NULL) + return; + + list_for_each_safe(ele, next, &head->list) { + data = list_entry(ele, struct hppfs_data, list); + kfree(data); + } + kfree(head); +} + +static struct hppfs_data *hppfs_get_data(int fd, int filter, + struct file *proc_file, + struct file *hppfs_file, + loff_t *size_out) +{ + struct hppfs_data *data, *new, *head; + int n, err; + + err = -ENOMEM; + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) { + printk(KERN_ERR "hppfs_get_data : head allocation failed\n"); + goto failed; + } + + INIT_LIST_HEAD(&data->list); + + head = data; + *size_out = 0; + + if (filter) { + while ((n = read_proc(proc_file, data->contents, + sizeof(data->contents), NULL, 0)) > 0) + os_write_file(fd, data->contents, n); + err = os_shutdown_socket(fd, 0, 1); + if (err) { + printk(KERN_ERR "hppfs_get_data : failed to shut down " + "socket\n"); + goto failed_free; + } + } + while (1) { + n = os_read_file(fd, data->contents, sizeof(data->contents)); + if (n < 0) { + err = n; + printk(KERN_ERR "hppfs_get_data : read failed, " + "errno = %d\n", err); + goto failed_free; + } else if (n == 0) + break; + + *size_out += n; + + if (n < sizeof(data->contents)) + break; + + new = kmalloc(sizeof(*data), GFP_KERNEL); + if (new == 0) { + printk(KERN_ERR "hppfs_get_data : data allocation " + "failed\n"); + err = -ENOMEM; + goto failed_free; + } + + INIT_LIST_HEAD(&new->list); + list_add(&new->list, &data->list); + data = new; + } + return head; + + failed_free: + free_contents(head); + failed: + return ERR_PTR(err); +} + +static struct hppfs_private *hppfs_data(void) +{ + struct hppfs_private *data; + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return data; + + *data = ((struct hppfs_private ) { .host_fd = -1, + .len = -1, + .contents = NULL } ); + return data; +} + +static int file_mode(int fmode) +{ + if (fmode == (FMODE_READ | FMODE_WRITE)) + return O_RDWR; + if (fmode == FMODE_READ) + return O_RDONLY; + if (fmode == FMODE_WRITE) + return O_WRONLY; + return 0; +} + +static int hppfs_open(struct inode *inode, struct file *file) +{ + struct hppfs_private *data; + struct vfsmount *proc_mnt; + struct dentry *proc_dentry; + char *host_file; + int err, fd, type, filter; + + err = -ENOMEM; + data = hppfs_data(); + if (data == NULL) + goto out; + + host_file = dentry_name(file->f_path.dentry, strlen("/rw")); + if (host_file == NULL) + goto out_free2; + + proc_dentry = HPPFS_I(inode)->proc_dentry; + proc_mnt = inode->i_sb->s_fs_info; + + /* XXX This isn't closed anywhere */ + data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), + file_mode(file->f_mode)); + err = PTR_ERR(data->proc_file); + if (IS_ERR(data->proc_file)) + goto out_free1; + + type = os_file_type(host_file); + if (type == OS_TYPE_FILE) { + fd = os_open_file(host_file, of_read(OPENFLAGS()), 0); + if (fd >= 0) + data->host_fd = fd; + else + printk(KERN_ERR "hppfs_open : failed to open '%s', " + "errno = %d\n", host_file, -fd); + + data->contents = NULL; + } else if (type == OS_TYPE_DIR) { + fd = open_host_sock(host_file, &filter); + if (fd > 0) { + data->contents = hppfs_get_data(fd, filter, + data->proc_file, + file, &data->len); + if (!IS_ERR(data->contents)) + data->host_fd = fd; + } else + printk(KERN_ERR "hppfs_open : failed to open a socket " + "in '%s', errno = %d\n", host_file, -fd); + } + kfree(host_file); + + file->private_data = data; + return 0; + + out_free1: + kfree(host_file); + out_free2: + free_contents(data->contents); + kfree(data); + out: + return err; +} + +static int hppfs_dir_open(struct inode *inode, struct file *file) +{ + struct hppfs_private *data; + struct vfsmount *proc_mnt; + struct dentry *proc_dentry; + int err; + + err = -ENOMEM; + data = hppfs_data(); + if (data == NULL) + goto out; + + proc_dentry = HPPFS_I(inode)->proc_dentry; + proc_mnt = inode->i_sb->s_fs_info; + data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), + file_mode(file->f_mode)); + err = PTR_ERR(data->proc_file); + if (IS_ERR(data->proc_file)) + goto out_free; + + file->private_data = data; + return 0; + + out_free: + kfree(data); + out: + return err; +} + +static loff_t hppfs_llseek(struct file *file, loff_t off, int where) +{ + struct hppfs_private *data = file->private_data; + struct file *proc_file = data->proc_file; + loff_t (*llseek)(struct file *, loff_t, int); + loff_t ret; + + llseek = proc_file->f_path.dentry->d_inode->i_fop->llseek; + if (llseek != NULL) { + ret = (*llseek)(proc_file, off, where); + if (ret < 0) + return ret; + } + + return default_llseek(file, off, where); +} + +static const struct file_operations hppfs_file_fops = { + .owner = NULL, + .llseek = hppfs_llseek, + .read = hppfs_read, + .write = hppfs_write, + .open = hppfs_open, +}; + +struct hppfs_dirent { + void *vfs_dirent; + filldir_t filldir; + struct dentry *dentry; +}; + +static int hppfs_filldir(void *d, const char *name, int size, + loff_t offset, u64 inode, unsigned int type) +{ + struct hppfs_dirent *dirent = d; + + if (file_removed(dirent->dentry, name)) + return 0; + + return (*dirent->filldir)(dirent->vfs_dirent, name, size, offset, + inode, type); +} + +static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir) +{ + struct hppfs_private *data = file->private_data; + struct file *proc_file = data->proc_file; + int (*readdir)(struct file *, void *, filldir_t); + struct hppfs_dirent dirent = ((struct hppfs_dirent) + { .vfs_dirent = ent, + .filldir = filldir, + .dentry = file->f_path.dentry + }); + int err; + + readdir = proc_file->f_path.dentry->d_inode->i_fop->readdir; + + proc_file->f_pos = file->f_pos; + err = (*readdir)(proc_file, &dirent, hppfs_filldir); + file->f_pos = proc_file->f_pos; + + return err; +} + +static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + return 0; +} + +static const struct file_operations hppfs_dir_fops = { + .owner = NULL, + .readdir = hppfs_readdir, + .open = hppfs_dir_open, + .fsync = hppfs_fsync, +}; + +static int hppfs_statfs(struct dentry *dentry, struct kstatfs *sf) +{ + sf->f_blocks = 0; + sf->f_bfree = 0; + sf->f_bavail = 0; + sf->f_files = 0; + sf->f_ffree = 0; + sf->f_type = HPPFS_SUPER_MAGIC; + return 0; +} + +static struct inode *hppfs_alloc_inode(struct super_block *sb) +{ + struct hppfs_inode_info *hi; + + hi = kmalloc(sizeof(*hi), GFP_KERNEL); + if (!hi) + return NULL; + + hi->proc_dentry = NULL; + inode_init_once(&hi->vfs_inode); + return &hi->vfs_inode; +} + +void hppfs_delete_inode(struct inode *ino) +{ + dput(HPPFS_I(ino)->proc_dentry); + mntput(ino->i_sb->s_fs_info); + + clear_inode(ino); +} + +static void hppfs_destroy_inode(struct inode *inode) +{ + kfree(HPPFS_I(inode)); +} + +static const struct super_operations hppfs_sbops = { + .alloc_inode = hppfs_alloc_inode, + .destroy_inode = hppfs_destroy_inode, + .delete_inode = hppfs_delete_inode, + .statfs = hppfs_statfs, +}; + +static int hppfs_readlink(struct dentry *dentry, char __user *buffer, + int buflen) +{ + struct dentry *proc_dentry; + + proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; + return proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer, + buflen); +} + +static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct dentry *proc_dentry; + + proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; + + return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd); +} + +int hppfs_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + return generic_permission(inode, mask, NULL); +} + +static const struct inode_operations hppfs_dir_iops = { + .lookup = hppfs_lookup, + .permission = hppfs_permission, +}; + +static const struct inode_operations hppfs_link_iops = { + .readlink = hppfs_readlink, + .follow_link = hppfs_follow_link, + .permission = hppfs_permission, +}; + +static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) +{ + struct inode *proc_ino = dentry->d_inode; + struct inode *inode = new_inode(sb); + + if (!inode) + return ERR_PTR(-ENOMEM); + + if (S_ISDIR(dentry->d_inode->i_mode)) { + inode->i_op = &hppfs_dir_iops; + inode->i_fop = &hppfs_dir_fops; + } else if (S_ISLNK(dentry->d_inode->i_mode)) { + inode->i_op = &hppfs_link_iops; + inode->i_fop = &hppfs_file_fops; + } else { + inode->i_op = &hppfs_file_iops; + inode->i_fop = &hppfs_file_fops; + } + + HPPFS_I(inode)->proc_dentry = dget(dentry); + + inode->i_uid = proc_ino->i_uid; + inode->i_gid = proc_ino->i_gid; + inode->i_atime = proc_ino->i_atime; + inode->i_mtime = proc_ino->i_mtime; + inode->i_ctime = proc_ino->i_ctime; + inode->i_ino = proc_ino->i_ino; + inode->i_mode = proc_ino->i_mode; + inode->i_nlink = proc_ino->i_nlink; + inode->i_size = proc_ino->i_size; + inode->i_blocks = proc_ino->i_blocks; + + return inode; +} + +static int hppfs_fill_super(struct super_block *sb, void *d, int silent) +{ + struct inode *root_inode; + struct vfsmount *proc_mnt; + int err = -ENOENT; + + proc_mnt = do_kern_mount("proc", 0, "proc", NULL); + if (IS_ERR(proc_mnt)) + goto out; + + sb->s_blocksize = 1024; + sb->s_blocksize_bits = 10; + sb->s_magic = HPPFS_SUPER_MAGIC; + sb->s_op = &hppfs_sbops; + sb->s_fs_info = proc_mnt; + + err = -ENOMEM; + root_inode = get_inode(sb, proc_mnt->mnt_sb->s_root); + if (!root_inode) + goto out_mntput; + + sb->s_root = d_alloc_root(root_inode); + if (!sb->s_root) + goto out_iput; + + return 0; + + out_iput: + iput(root_inode); + out_mntput: + mntput(proc_mnt); + out: + return(err); +} + +static int hppfs_read_super(struct file_system_type *type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) +{ + return get_sb_nodev(type, flags, data, hppfs_fill_super, mnt); +} + +static struct file_system_type hppfs_type = { + .owner = THIS_MODULE, + .name = "hppfs", + .get_sb = hppfs_read_super, + .kill_sb = kill_anon_super, + .fs_flags = 0, +}; + +static int __init init_hppfs(void) +{ + return register_filesystem(&hppfs_type); +} + +static void __exit exit_hppfs(void) +{ + unregister_filesystem(&hppfs_type); +} + +module_init(init_hppfs) +module_exit(exit_hppfs) +MODULE_LICENSE("GPL"); diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c deleted file mode 100644 index 65077aa90f0..00000000000 --- a/fs/hppfs/hppfs_kern.c +++ /dev/null @@ -1,771 +0,0 @@ -/* - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "os.h" - -static struct inode *get_inode(struct super_block *, struct dentry *); - -struct hppfs_data { - struct list_head list; - char contents[PAGE_SIZE - sizeof(struct list_head)]; -}; - -struct hppfs_private { - struct file *proc_file; - int host_fd; - loff_t len; - struct hppfs_data *contents; -}; - -struct hppfs_inode_info { - struct dentry *proc_dentry; - struct inode vfs_inode; -}; - -static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode) -{ - return container_of(inode, struct hppfs_inode_info, vfs_inode); -} - -#define HPPFS_SUPER_MAGIC 0xb00000ee - -static const struct super_operations hppfs_sbops; - -static int is_pid(struct dentry *dentry) -{ - struct super_block *sb; - int i; - - sb = dentry->d_sb; - if (dentry->d_parent != sb->s_root) - return 0; - - for (i = 0; i < dentry->d_name.len; i++) { - if (!isdigit(dentry->d_name.name[i])) - return 0; - } - return 1; -} - -static char *dentry_name(struct dentry *dentry, int extra) -{ - struct dentry *parent; - char *root, *name; - const char *seg_name; - int len, seg_len; - - len = 0; - parent = dentry; - while (parent->d_parent != parent) { - if (is_pid(parent)) - len += strlen("pid") + 1; - else len += parent->d_name.len + 1; - parent = parent->d_parent; - } - - root = "proc"; - len += strlen(root); - name = kmalloc(len + extra + 1, GFP_KERNEL); - if (name == NULL) - return NULL; - - name[len] = '\0'; - parent = dentry; - while (parent->d_parent != parent) { - if (is_pid(parent)) { - seg_name = "pid"; - seg_len = strlen("pid"); - } - else { - seg_name = parent->d_name.name; - seg_len = parent->d_name.len; - } - - len -= seg_len + 1; - name[len] = '/'; - strncpy(&name[len + 1], seg_name, seg_len); - parent = parent->d_parent; - } - strncpy(name, root, strlen(root)); - return name; -} - -static int file_removed(struct dentry *dentry, const char *file) -{ - char *host_file; - int extra, fd; - - extra = 0; - if (file != NULL) - extra += strlen(file) + 1; - - host_file = dentry_name(dentry, extra + strlen("/remove")); - if (host_file == NULL) { - printk(KERN_ERR "file_removed : allocation failed\n"); - return -ENOMEM; - } - - if (file != NULL) { - strcat(host_file, "/"); - strcat(host_file, file); - } - strcat(host_file, "/remove"); - - fd = os_open_file(host_file, of_read(OPENFLAGS()), 0); - kfree(host_file); - if (fd > 0) { - os_close_file(fd); - return 1; - } - return 0; -} - -static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, - struct nameidata *nd) -{ - struct dentry *proc_dentry, *new, *parent; - struct inode *inode; - int err, deleted; - - deleted = file_removed(dentry, NULL); - if (deleted < 0) - return ERR_PTR(deleted); - else if (deleted) - return ERR_PTR(-ENOENT); - - err = -ENOMEM; - parent = HPPFS_I(ino)->proc_dentry; - mutex_lock(&parent->d_inode->i_mutex); - proc_dentry = d_lookup(parent, &dentry->d_name); - if (proc_dentry == NULL) { - proc_dentry = d_alloc(parent, &dentry->d_name); - if (proc_dentry == NULL) { - mutex_unlock(&parent->d_inode->i_mutex); - goto out; - } - new = (*parent->d_inode->i_op->lookup)(parent->d_inode, - proc_dentry, NULL); - if (new) { - dput(proc_dentry); - proc_dentry = new; - } - } - mutex_unlock(&parent->d_inode->i_mutex); - - if (IS_ERR(proc_dentry)) - return proc_dentry; - - err = -ENOMEM; - inode = get_inode(ino->i_sb, proc_dentry); - if (!inode) - goto out_dput; - - d_add(dentry, inode); - return NULL; - - out_dput: - dput(proc_dentry); - out: - return ERR_PTR(err); -} - -static const struct inode_operations hppfs_file_iops = { -}; - -static ssize_t read_proc(struct file *file, char __user *buf, ssize_t count, - loff_t *ppos, int is_user) -{ - ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); - ssize_t n; - - read = file->f_path.dentry->d_inode->i_fop->read; - - if (!is_user) - set_fs(KERNEL_DS); - - n = (*read)(file, buf, count, &file->f_pos); - - if (!is_user) - set_fs(USER_DS); - - if (ppos) - *ppos = file->f_pos; - return n; -} - -static ssize_t hppfs_read_file(int fd, char __user *buf, ssize_t count) -{ - ssize_t n; - int cur, err; - char *new_buf; - - n = -ENOMEM; - new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (new_buf == NULL) { - printk(KERN_ERR "hppfs_read_file : kmalloc failed\n"); - goto out; - } - n = 0; - while (count > 0) { - cur = min_t(ssize_t, count, PAGE_SIZE); - err = os_read_file(fd, new_buf, cur); - if (err < 0) { - printk(KERN_ERR "hppfs_read : read failed, " - "errno = %d\n", err); - n = err; - goto out_free; - } else if (err == 0) - break; - - if (copy_to_user(buf, new_buf, err)) { - n = -EFAULT; - goto out_free; - } - n += err; - count -= err; - } - out_free: - kfree(new_buf); - out: - return n; -} - -static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct hppfs_private *hppfs = file->private_data; - struct hppfs_data *data; - loff_t off; - int err; - - if (hppfs->contents != NULL) { - int rem; - - if (*ppos >= hppfs->len) - return 0; - - data = hppfs->contents; - off = *ppos; - while (off >= sizeof(data->contents)) { - data = list_entry(data->list.next, struct hppfs_data, - list); - off -= sizeof(data->contents); - } - - if (off + count > hppfs->len) - count = hppfs->len - off; - rem = copy_to_user(buf, &data->contents[off], count); - *ppos += count - rem; - if (rem > 0) - return -EFAULT; - } else if (hppfs->host_fd != -1) { - err = os_seek_file(hppfs->host_fd, *ppos); - if (err) { - printk(KERN_ERR "hppfs_read : seek failed, " - "errno = %d\n", err); - return err; - } - count = hppfs_read_file(hppfs->host_fd, buf, count); - if (count > 0) - *ppos += count; - } - else count = read_proc(hppfs->proc_file, buf, count, ppos, 1); - - return count; -} - -static ssize_t hppfs_write(struct file *file, const char __user *buf, - size_t len, loff_t *ppos) -{ - struct hppfs_private *data = file->private_data; - struct file *proc_file = data->proc_file; - ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); - - write = proc_file->f_path.dentry->d_inode->i_fop->write; - return (*write)(proc_file, buf, len, ppos); -} - -static int open_host_sock(char *host_file, int *filter_out) -{ - char *end; - int fd; - - end = &host_file[strlen(host_file)]; - strcpy(end, "/rw"); - *filter_out = 1; - fd = os_connect_socket(host_file); - if (fd > 0) - return fd; - - strcpy(end, "/r"); - *filter_out = 0; - fd = os_connect_socket(host_file); - return fd; -} - -static void free_contents(struct hppfs_data *head) -{ - struct hppfs_data *data; - struct list_head *ele, *next; - - if (head == NULL) - return; - - list_for_each_safe(ele, next, &head->list) { - data = list_entry(ele, struct hppfs_data, list); - kfree(data); - } - kfree(head); -} - -static struct hppfs_data *hppfs_get_data(int fd, int filter, - struct file *proc_file, - struct file *hppfs_file, - loff_t *size_out) -{ - struct hppfs_data *data, *new, *head; - int n, err; - - err = -ENOMEM; - data = kmalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) { - printk(KERN_ERR "hppfs_get_data : head allocation failed\n"); - goto failed; - } - - INIT_LIST_HEAD(&data->list); - - head = data; - *size_out = 0; - - if (filter) { - while ((n = read_proc(proc_file, data->contents, - sizeof(data->contents), NULL, 0)) > 0) - os_write_file(fd, data->contents, n); - err = os_shutdown_socket(fd, 0, 1); - if (err) { - printk(KERN_ERR "hppfs_get_data : failed to shut down " - "socket\n"); - goto failed_free; - } - } - while (1) { - n = os_read_file(fd, data->contents, sizeof(data->contents)); - if (n < 0) { - err = n; - printk(KERN_ERR "hppfs_get_data : read failed, " - "errno = %d\n", err); - goto failed_free; - } else if (n == 0) - break; - - *size_out += n; - - if (n < sizeof(data->contents)) - break; - - new = kmalloc(sizeof(*data), GFP_KERNEL); - if (new == 0) { - printk(KERN_ERR "hppfs_get_data : data allocation " - "failed\n"); - err = -ENOMEM; - goto failed_free; - } - - INIT_LIST_HEAD(&new->list); - list_add(&new->list, &data->list); - data = new; - } - return head; - - failed_free: - free_contents(head); - failed: - return ERR_PTR(err); -} - -static struct hppfs_private *hppfs_data(void) -{ - struct hppfs_private *data; - - data = kmalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) - return data; - - *data = ((struct hppfs_private ) { .host_fd = -1, - .len = -1, - .contents = NULL } ); - return data; -} - -static int file_mode(int fmode) -{ - if (fmode == (FMODE_READ | FMODE_WRITE)) - return O_RDWR; - if (fmode == FMODE_READ) - return O_RDONLY; - if (fmode == FMODE_WRITE) - return O_WRONLY; - return 0; -} - -static int hppfs_open(struct inode *inode, struct file *file) -{ - struct hppfs_private *data; - struct vfsmount *proc_mnt; - struct dentry *proc_dentry; - char *host_file; - int err, fd, type, filter; - - err = -ENOMEM; - data = hppfs_data(); - if (data == NULL) - goto out; - - host_file = dentry_name(file->f_path.dentry, strlen("/rw")); - if (host_file == NULL) - goto out_free2; - - proc_dentry = HPPFS_I(inode)->proc_dentry; - proc_mnt = inode->i_sb->s_fs_info; - - /* XXX This isn't closed anywhere */ - data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), - file_mode(file->f_mode)); - err = PTR_ERR(data->proc_file); - if (IS_ERR(data->proc_file)) - goto out_free1; - - type = os_file_type(host_file); - if (type == OS_TYPE_FILE) { - fd = os_open_file(host_file, of_read(OPENFLAGS()), 0); - if (fd >= 0) - data->host_fd = fd; - else - printk(KERN_ERR "hppfs_open : failed to open '%s', " - "errno = %d\n", host_file, -fd); - - data->contents = NULL; - } else if (type == OS_TYPE_DIR) { - fd = open_host_sock(host_file, &filter); - if (fd > 0) { - data->contents = hppfs_get_data(fd, filter, - data->proc_file, - file, &data->len); - if (!IS_ERR(data->contents)) - data->host_fd = fd; - } else - printk(KERN_ERR "hppfs_open : failed to open a socket " - "in '%s', errno = %d\n", host_file, -fd); - } - kfree(host_file); - - file->private_data = data; - return 0; - - out_free1: - kfree(host_file); - out_free2: - free_contents(data->contents); - kfree(data); - out: - return err; -} - -static int hppfs_dir_open(struct inode *inode, struct file *file) -{ - struct hppfs_private *data; - struct vfsmount *proc_mnt; - struct dentry *proc_dentry; - int err; - - err = -ENOMEM; - data = hppfs_data(); - if (data == NULL) - goto out; - - proc_dentry = HPPFS_I(inode)->proc_dentry; - proc_mnt = inode->i_sb->s_fs_info; - data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), - file_mode(file->f_mode)); - err = PTR_ERR(data->proc_file); - if (IS_ERR(data->proc_file)) - goto out_free; - - file->private_data = data; - return 0; - - out_free: - kfree(data); - out: - return err; -} - -static loff_t hppfs_llseek(struct file *file, loff_t off, int where) -{ - struct hppfs_private *data = file->private_data; - struct file *proc_file = data->proc_file; - loff_t (*llseek)(struct file *, loff_t, int); - loff_t ret; - - llseek = proc_file->f_path.dentry->d_inode->i_fop->llseek; - if (llseek != NULL) { - ret = (*llseek)(proc_file, off, where); - if (ret < 0) - return ret; - } - - return default_llseek(file, off, where); -} - -static const struct file_operations hppfs_file_fops = { - .owner = NULL, - .llseek = hppfs_llseek, - .read = hppfs_read, - .write = hppfs_write, - .open = hppfs_open, -}; - -struct hppfs_dirent { - void *vfs_dirent; - filldir_t filldir; - struct dentry *dentry; -}; - -static int hppfs_filldir(void *d, const char *name, int size, - loff_t offset, u64 inode, unsigned int type) -{ - struct hppfs_dirent *dirent = d; - - if (file_removed(dirent->dentry, name)) - return 0; - - return (*dirent->filldir)(dirent->vfs_dirent, name, size, offset, - inode, type); -} - -static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir) -{ - struct hppfs_private *data = file->private_data; - struct file *proc_file = data->proc_file; - int (*readdir)(struct file *, void *, filldir_t); - struct hppfs_dirent dirent = ((struct hppfs_dirent) - { .vfs_dirent = ent, - .filldir = filldir, - .dentry = file->f_path.dentry - }); - int err; - - readdir = proc_file->f_path.dentry->d_inode->i_fop->readdir; - - proc_file->f_pos = file->f_pos; - err = (*readdir)(proc_file, &dirent, hppfs_filldir); - file->f_pos = proc_file->f_pos; - - return err; -} - -static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync) -{ - return 0; -} - -static const struct file_operations hppfs_dir_fops = { - .owner = NULL, - .readdir = hppfs_readdir, - .open = hppfs_dir_open, - .fsync = hppfs_fsync, -}; - -static int hppfs_statfs(struct dentry *dentry, struct kstatfs *sf) -{ - sf->f_blocks = 0; - sf->f_bfree = 0; - sf->f_bavail = 0; - sf->f_files = 0; - sf->f_ffree = 0; - sf->f_type = HPPFS_SUPER_MAGIC; - return 0; -} - -static struct inode *hppfs_alloc_inode(struct super_block *sb) -{ - struct hppfs_inode_info *hi; - - hi = kmalloc(sizeof(*hi), GFP_KERNEL); - if (!hi) - return NULL; - - hi->proc_dentry = NULL; - inode_init_once(&hi->vfs_inode); - return &hi->vfs_inode; -} - -void hppfs_delete_inode(struct inode *ino) -{ - dput(HPPFS_I(ino)->proc_dentry); - mntput(ino->i_sb->s_fs_info); - - clear_inode(ino); -} - -static void hppfs_destroy_inode(struct inode *inode) -{ - kfree(HPPFS_I(inode)); -} - -static const struct super_operations hppfs_sbops = { - .alloc_inode = hppfs_alloc_inode, - .destroy_inode = hppfs_destroy_inode, - .delete_inode = hppfs_delete_inode, - .statfs = hppfs_statfs, -}; - -static int hppfs_readlink(struct dentry *dentry, char __user *buffer, - int buflen) -{ - struct dentry *proc_dentry; - - proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; - return proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer, - buflen); -} - -static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) -{ - struct dentry *proc_dentry; - - proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; - - return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd); -} - -int hppfs_permission(struct inode *inode, int mask, struct nameidata *nd) -{ - return generic_permission(inode, mask, NULL); -} - -static const struct inode_operations hppfs_dir_iops = { - .lookup = hppfs_lookup, - .permission = hppfs_permission, -}; - -static const struct inode_operations hppfs_link_iops = { - .readlink = hppfs_readlink, - .follow_link = hppfs_follow_link, - .permission = hppfs_permission, -}; - -static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) -{ - struct inode *proc_ino = dentry->d_inode; - struct inode *inode = new_inode(sb); - - if (!inode) - return ERR_PTR(-ENOMEM); - - if (S_ISDIR(dentry->d_inode->i_mode)) { - inode->i_op = &hppfs_dir_iops; - inode->i_fop = &hppfs_dir_fops; - } else if (S_ISLNK(dentry->d_inode->i_mode)) { - inode->i_op = &hppfs_link_iops; - inode->i_fop = &hppfs_file_fops; - } else { - inode->i_op = &hppfs_file_iops; - inode->i_fop = &hppfs_file_fops; - } - - HPPFS_I(inode)->proc_dentry = dget(dentry); - - inode->i_uid = proc_ino->i_uid; - inode->i_gid = proc_ino->i_gid; - inode->i_atime = proc_ino->i_atime; - inode->i_mtime = proc_ino->i_mtime; - inode->i_ctime = proc_ino->i_ctime; - inode->i_ino = proc_ino->i_ino; - inode->i_mode = proc_ino->i_mode; - inode->i_nlink = proc_ino->i_nlink; - inode->i_size = proc_ino->i_size; - inode->i_blocks = proc_ino->i_blocks; - - return inode; -} - -static int hppfs_fill_super(struct super_block *sb, void *d, int silent) -{ - struct inode *root_inode; - struct vfsmount *proc_mnt; - int err = -ENOENT; - - proc_mnt = do_kern_mount("proc", 0, "proc", NULL); - if (IS_ERR(proc_mnt)) - goto out; - - sb->s_blocksize = 1024; - sb->s_blocksize_bits = 10; - sb->s_magic = HPPFS_SUPER_MAGIC; - sb->s_op = &hppfs_sbops; - sb->s_fs_info = proc_mnt; - - err = -ENOMEM; - root_inode = get_inode(sb, proc_mnt->mnt_sb->s_root); - if (!root_inode) - goto out_mntput; - - sb->s_root = d_alloc_root(root_inode); - if (!sb->s_root) - goto out_iput; - - return 0; - - out_iput: - iput(root_inode); - out_mntput: - mntput(proc_mnt); - out: - return(err); -} - -static int hppfs_read_super(struct file_system_type *type, - int flags, const char *dev_name, - void *data, struct vfsmount *mnt) -{ - return get_sb_nodev(type, flags, data, hppfs_fill_super, mnt); -} - -static struct file_system_type hppfs_type = { - .owner = THIS_MODULE, - .name = "hppfs", - .get_sb = hppfs_read_super, - .kill_sb = kill_anon_super, - .fs_flags = 0, -}; - -static int __init init_hppfs(void) -{ - return register_filesystem(&hppfs_type); -} - -static void __exit exit_hppfs(void) -{ - unregister_filesystem(&hppfs_type); -} - -module_init(init_hppfs) -module_exit(exit_hppfs) -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 8dc4e37362a5dc910d704d52ac6542bfd49ddc2f Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 12 May 2008 14:02:04 -0700 Subject: ecryptfs: clean up (un)lock_parent dget(dentry->d_parent) --> dget_parent(dentry) unlock_parent() is racy and unnecessary. Replace single caller with unlock_dir(). There are several other suspect uses of ->d_parent in ecryptfs... Signed-off-by: Miklos Szeredi Cc: Michael Halcrow Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ecryptfs/inode.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 0a1397335a8..c92cc1c00aa 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -37,17 +37,11 @@ static struct dentry *lock_parent(struct dentry *dentry) { struct dentry *dir; - dir = dget(dentry->d_parent); + dir = dget_parent(dentry); mutex_lock_nested(&(dir->d_inode->i_mutex), I_MUTEX_PARENT); return dir; } -static void unlock_parent(struct dentry *dentry) -{ - mutex_unlock(&(dentry->d_parent->d_inode->i_mutex)); - dput(dentry->d_parent); -} - static void unlock_dir(struct dentry *dir) { mutex_unlock(&dir->d_inode->i_mutex); @@ -426,8 +420,9 @@ static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry) int rc = 0; struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); + struct dentry *lower_dir_dentry; - lock_parent(lower_dentry); + lower_dir_dentry = lock_parent(lower_dentry); rc = vfs_unlink(lower_dir_inode, lower_dentry); if (rc) { printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); @@ -439,7 +434,7 @@ static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry) dentry->d_inode->i_ctime = dir->i_ctime; d_drop(dentry); out_unlock: - unlock_parent(lower_dentry); + unlock_dir(lower_dir_dentry); return rc; } -- cgit v1.2.3 From bb45d64224e5cafe8c8e0d18a20da998e5a7dc93 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 12 May 2008 14:02:06 -0700 Subject: ufs: remove unneeded ufs_put_inode prototype Signed-off-by: Christoph Hellwig Acked-by: Evgeniy Dushistov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ufs/ufs.h | 1 - 1 file changed, 1 deletion(-) (limited to 'fs') diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 244a1aaa940..11c035168ea 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h @@ -107,7 +107,6 @@ extern struct inode * ufs_new_inode (struct inode *, int); /* inode.c */ extern struct inode *ufs_iget(struct super_block *, unsigned long); -extern void ufs_put_inode (struct inode *); extern int ufs_write_inode (struct inode *, int); extern int ufs_sync_inode (struct inode *); extern void ufs_delete_inode (struct inode *); -- cgit v1.2.3 From 9377abd026bf9bde7db90dac09170034bf6d1cbf Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 12 May 2008 14:02:08 -0700 Subject: quota: don't call sync_fs() from vfs_quota_off() when there's no quota turn off Sometimes, vfs_quota_off() is called on a partially set up super block (for example when fill_super() fails for some reason). In such cases we cannot call ->sync_fs() because it can Oops because of not properly filled in super block. So in case we find there's not quota to turn off, we just skip everything and return which fixes the above problem. [akpm@linux-foundation.org: fxi tpyo] Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dquot.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'fs') diff --git a/fs/dquot.c b/fs/dquot.c index dfba1623ccc..5ac77da1995 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -1491,6 +1491,16 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) /* We need to serialize quota_off() for device */ mutex_lock(&dqopt->dqonoff_mutex); + + /* + * Skip everything if there's nothing to do. We have to do this because + * sometimes we are called when fill_super() failed and calling + * sync_fs() in such cases does no good. + */ + if (!sb_any_quota_enabled(sb) && !sb_any_quota_suspended(sb)) { + mutex_unlock(&dqopt->dqonoff_mutex); + return 0; + } for (cnt = 0; cnt < MAXQUOTAS; cnt++) { toputinode[cnt] = NULL; if (type != -1 && cnt != type) -- cgit v1.2.3 From 289f8e27ed435dcbefad132def06f4e84351e94f Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Mon, 12 May 2008 14:02:13 -0700 Subject: capabilities: add bounding set to /proc/self/status There is currently no way to query the bounding set of another task. As there appears to be no security reason not to, and as Michael Kerrisk points out the following valid reasons to do so exist: * consistency (I can see all of the other per-thread/process sets in /proc/.../status) * debugging -- I could imagine that it would make the job of debugging an application that uses capabilities a little simpler. this patch adds the bounding set to /proc/self/status right after the effective set. Signed-off-by: Serge E. Hallyn Acked-by: Michael Kerrisk Acked-by: Andrew G. Morgan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/array.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs') diff --git a/fs/proc/array.c b/fs/proc/array.c index dca997a93bf..9e3b8c33c24 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -298,6 +298,7 @@ static inline void task_cap(struct seq_file *m, struct task_struct *p) render_cap_t(m, "CapInh:\t", &p->cap_inheritable); render_cap_t(m, "CapPrm:\t", &p->cap_permitted); render_cap_t(m, "CapEff:\t", &p->cap_effective); + render_cap_t(m, "CapBnd:\t", &p->cap_bset); } static inline void task_context_switch_counts(struct seq_file *m, -- cgit v1.2.3 From 706322496b3a58af3cf258db2b553d6933656eef Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Mon, 12 May 2008 14:02:21 -0700 Subject: Fix hfsplus oops on image without extents Fix an oops with a corrupted hfs+ image. See http://bugzilla.kernel.org/show_bug.cgi?id=10548 for details. Problem is that we call hfs_btree_open() from hfsplus_fill_super() to set HFSPLUS_SB(sb).[ext_tree|cat_tree] Both trees are still NULL at this moment. If hfs_btree_open() fails for any reason it calls iput() on the page, which gets to hfsplus_releasepage() which tries to access HFSPLUS_SB(sb).* which is still NULL and oopses while dereferencing it. [akpm@linux-foundation.org: build fix] Signed-off-by: Eric Sesterhenn Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hfsplus/inode.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index d53b2af91c2..67e1c8b467c 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -65,6 +65,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) BUG(); return 0; } + if (!tree) + return 0; if (tree->node_size >= PAGE_CACHE_SIZE) { nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT); spin_lock(&tree->hash_lock); -- cgit v1.2.3 From 4cd1a8fc3d3cd740416b14ece2693dbb5d065eaf Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Mon, 12 May 2008 14:02:31 -0700 Subject: memcg: fix possible panic when CONFIG_MM_OWNER=y When mm destruction happens, we should pass mm_update_next_owner() the old mm. But unfortunately new mm is passed in exec_mmap(). Thus, kernel panic is possible when a multi-threaded process uses exec(). Also, the owner member comment description is wrong. mm->owner does not necessarily point to the thread group leader. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: KOSAKI Motohiro Acked-by: Balbir Singh Cc: "Paul Menage" Cc: "KAMEZAWA Hiroyuki" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/exec.c b/fs/exec.c index aeaa9791d8b..1f8a24aa1f8 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -736,7 +736,7 @@ static int exec_mmap(struct mm_struct *mm) tsk->active_mm = mm; activate_mm(active_mm, mm); task_unlock(tsk); - mm_update_next_owner(mm); + mm_update_next_owner(old_mm); arch_pick_mmap_layout(mm); if (old_mm) { up_read(&old_mm->mmap_sem); -- cgit v1.2.3 From 78bb6cb9a890d3d50ca3b02fce9223d3e734ab9b Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 12 May 2008 14:02:32 -0700 Subject: fuse: add flag to turn on big writes Prior to 2.6.26 fuse only supported single page write requests. In theory all fuse filesystem should be able support bigger than 4k writes, as there's nothing in the API to prevent it. Unfortunately there's a known case in NTFS-3G where big writes cause filesystem corruption. There could also be other filesystems, where the lack of testing with big write requests would result in bugs. To prevent such problems on a kernel upgrade, disable big writes by default, but let filesystems set a flag to turn it on. Signed-off-by: Miklos Szeredi Cc: Szabolcs Szakacsits Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fuse/file.c | 2 ++ fs/fuse/fuse_i.h | 3 +++ fs/fuse/inode.c | 5 ++++- 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/fuse/file.c b/fs/fuse/file.c index f28cf8b46f8..8092f0d9fd1 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -804,6 +804,8 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req, if (offset == PAGE_CACHE_SIZE) offset = 0; + if (!fc->big_writes) + break; } while (iov_iter_count(ii) && count < fc->max_write && req->num_pages < FUSE_MAX_PAGES_PER_REQ && offset == 0); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index dadffa21a20..bae948657c4 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -404,6 +404,9 @@ struct fuse_conn { /** Is bmap not implemented by fs? */ unsigned no_bmap : 1; + /** Do multi-page cached writes */ + unsigned big_writes : 1; + /** The number of requests waiting for completion */ atomic_t num_waiting; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 79b61587383..fb77e096213 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -576,6 +576,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) fc->no_lock = 1; if (arg->flags & FUSE_ATOMIC_O_TRUNC) fc->atomic_o_trunc = 1; + if (arg->flags & FUSE_BIG_WRITES) + fc->big_writes = 1; } else { ra_pages = fc->max_read / PAGE_CACHE_SIZE; fc->no_lock = 1; @@ -599,7 +601,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) arg->major = FUSE_KERNEL_VERSION; arg->minor = FUSE_KERNEL_MINOR_VERSION; arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; - arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC; + arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | + FUSE_BIG_WRITES; req->in.h.opcode = FUSE_INIT; req->in.numargs = 1; req->in.args[0].size = sizeof(*arg); -- cgit v1.2.3 From f36f21ecca9ee688301174e5f2e0827827a7a7ff Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 12 May 2008 14:02:33 -0700 Subject: Fix misuses of bdevname() bdevname() fills the buffer that it is given as a parameter, so calling strcpy() or snprintf() on the returned value is redundant (and probably not guaranteed to work - I don't think strcpy and snprintf support overlapping buffers.) Signed-off-by: Jean Delvare Cc: Stephen Tweedie Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/mballoc.c | 6 ++---- fs/jbd2/journal.c | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index fbec2ef9379..b128bdc0f55 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2639,8 +2639,7 @@ static int ext4_mb_init_per_dev_proc(struct super_block *sb) struct proc_dir_entry *proc; char devname[64]; - snprintf(devname, sizeof(devname) - 1, "%s", - bdevname(sb->s_bdev, devname)); + bdevname(sb->s_bdev, devname); sbi->s_mb_proc = proc_mkdir(devname, proc_root_ext4); MB_PROC_HANDLER(EXT4_MB_STATS_NAME, stats); @@ -2674,8 +2673,7 @@ static int ext4_mb_destroy_per_dev_proc(struct super_block *sb) if (sbi->s_mb_proc == NULL) return -EINVAL; - snprintf(devname, sizeof(devname) - 1, "%s", - bdevname(sb->s_bdev, devname)); + bdevname(sb->s_bdev, devname); remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc); remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc); remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc); diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 53632e3e845..2e24567c4a7 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -901,7 +901,7 @@ static void jbd2_stats_proc_init(journal_t *journal) { char name[BDEVNAME_SIZE]; - snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name)); + bdevname(journal->j_dev, name); journal->j_proc_entry = proc_mkdir(name, proc_jbd2_stats); if (journal->j_proc_entry) { proc_create_data("history", S_IRUGO, journal->j_proc_entry, @@ -915,7 +915,7 @@ static void jbd2_stats_proc_exit(journal_t *journal) { char name[BDEVNAME_SIZE]; - snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name)); + bdevname(journal->j_dev, name); remove_proc_entry("info", journal->j_proc_entry); remove_proc_entry("history", journal->j_proc_entry); remove_proc_entry(name, proc_jbd2_stats); -- cgit v1.2.3 From 43f14d856f013a4cc63da2c765617c665274338c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 12 May 2008 14:02:40 -0700 Subject: eCryptFS: fix imbalanced mutex locking Fix imbalanced calls for mutex lock/unlock on ecryptfs_daemon_hash_mux Revealed by Ingo Molnar: http://lkml.org/lkml/2008/5/7/260 Signed-off-by: Cyrill Gorcunov Cc: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ecryptfs/miscdev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c index 788995efd1d..6560da1a58c 100644 --- a/fs/ecryptfs/miscdev.c +++ b/fs/ecryptfs/miscdev.c @@ -257,12 +257,14 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count, mutex_lock(&daemon->mux); if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { rc = 0; + mutex_unlock(&ecryptfs_daemon_hash_mux); printk(KERN_WARNING "%s: Attempt to read from zombified " "daemon\n", __func__); goto out_unlock_daemon; } if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) { rc = 0; + mutex_unlock(&ecryptfs_daemon_hash_mux); goto out_unlock_daemon; } /* This daemon will not go away so long as this flag is set */ -- cgit v1.2.3 From 77c57ec89682c73785d12d51a6d1f873b292fa42 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 13 May 2008 21:39:32 +0000 Subject: [CIFS] don't explicitly do a FindClose on rewind when directory search has ended Do the following series of operations on a CIFS share: opendir(dir) readdir(dir) unlink(file in dir) rewinddir(dir) readdir(dir) If the readdir read all entries in the directory this will make CIFS throw an error like this: CIFS VFS: Send error in FindClose = -9 CIFS requests "Close at end of search" of the server by setting this bit when issuing FindFirst or FindNext. Therefore when all search entries are returned, the server may return "end of search" and close the search implicitly when this bit is set by the client on the request. We check for this when a readdir is explicitly closed - but when the client notices that a directory has changed after the last operation, we attempt to close the directory before reopening by reissuing a second FindFirst. But, the directory may already been implicitly closed (due to end of search) because the first readdir finished. So we only want to issue a FindClose call in this case when we don't expect it to already be closed. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/readdir.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 34ec32100c7..713c2511019 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -670,8 +670,11 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, (index_to_find < first_entry_in_buffer)) { /* close and restart search */ cFYI(1, ("search backing up - close and restart search")); - cifsFile->invalidHandle = true; - CIFSFindClose(xid, pTcon, cifsFile->netfid); + if (!cifsFile->srch_inf.endOfSearch && + !cifsFile->invalidHandle) { + cifsFile->invalidHandle = true; + CIFSFindClose(xid, pTcon, cifsFile->netfid); + } kfree(cifsFile->search_resume_name); cifsFile->search_resume_name = NULL; if (cifsFile->srch_inf.ntwrk_buf_start) { -- cgit v1.2.3 From dfc5d03f12e706c19ee37734184ea96582ef931d Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 13 May 2008 19:11:51 -0400 Subject: ext4: correct mount option parsing to detect when quota options can be changed We should not allow user to change quota mount options when quota is just suspended. It would make mount options and internal quota state inconsistent. Also we should not allow user to change quota format when quota is turned on. On the other hand we can just silently ignore when some option is set to the value it already has (mount does this on remount). Cc: Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 52dd0679a4e..686ebcc2e6c 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -979,7 +979,7 @@ static int parse_options (char *options, struct super_block *sb, int data_opt = 0; int option; #ifdef CONFIG_QUOTA - int qtype; + int qtype, qfmt; char *qname; #endif @@ -1162,7 +1162,9 @@ static int parse_options (char *options, struct super_block *sb, case Opt_grpjquota: qtype = GRPQUOTA; set_qf_name: - if (sb_any_quota_enabled(sb)) { + if ((sb_any_quota_enabled(sb) || + sb_any_quota_suspended(sb)) && + !sbi->s_qf_names[qtype]) { printk(KERN_ERR "EXT4-fs: Cannot change journalled " "quota options when quota turned on.\n"); @@ -1200,7 +1202,9 @@ set_qf_name: case Opt_offgrpjquota: qtype = GRPQUOTA; clear_qf_name: - if (sb_any_quota_enabled(sb)) { + if ((sb_any_quota_enabled(sb) || + sb_any_quota_suspended(sb)) && + sbi->s_qf_names[qtype]) { printk(KERN_ERR "EXT4-fs: Cannot change " "journalled quota options when " "quota turned on.\n"); @@ -1213,10 +1217,20 @@ clear_qf_name: sbi->s_qf_names[qtype] = NULL; break; case Opt_jqfmt_vfsold: - sbi->s_jquota_fmt = QFMT_VFS_OLD; - break; + qfmt = QFMT_VFS_OLD; + goto set_qf_format; case Opt_jqfmt_vfsv0: - sbi->s_jquota_fmt = QFMT_VFS_V0; + qfmt = QFMT_VFS_V0; +set_qf_format: + if ((sb_any_quota_enabled(sb) || + sb_any_quota_suspended(sb)) && + sbi->s_jquota_fmt != qfmt) { + printk(KERN_ERR "EXT4-fs: Cannot change " + "journaled quota options when " + "quota turned on.\n"); + return 0; + } + sbi->s_jquota_fmt = qfmt; break; case Opt_quota: case Opt_usrquota: -- cgit v1.2.3 From cd59e7b9781a35716b8a3e8c4aa2d48081d7daf7 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 13 May 2008 19:11:51 -0400 Subject: ext4: Fix mount messages when quota disabled When quota is disabled, we should not print 'journaled quota not supported' when user tried to mount non-journaled quota. Also fix typo in the message. Signed-off-by: Jan Kara Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 686ebcc2e6c..94a527261ca 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1255,6 +1255,9 @@ set_qf_format: case Opt_quota: case Opt_usrquota: case Opt_grpquota: + printk(KERN_ERR + "EXT4-fs: quota options not supported.\n"); + break; case Opt_usrjquota: case Opt_grpjquota: case Opt_offusrjquota: @@ -1262,7 +1265,7 @@ set_qf_format: case Opt_jqfmt_vfsold: case Opt_jqfmt_vfsv0: printk(KERN_ERR - "EXT4-fs: journalled quota options not " + "EXT4-fs: journaled quota options not " "supported.\n"); break; case Opt_noquota: -- cgit v1.2.3 From 0623543b3335c8e439cacf21af99bbf45da42c5a Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 13 May 2008 19:11:51 -0400 Subject: ext4: fix synchronization of quota files in journal=data mode In journal=data mode, it is not enough to do write_inode_now as done in vfs_quota_on() to write all data to their final location (which is needed for quota_read to work correctly). Calling journal_flush() does its job. Cc: Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 94a527261ca..cddf7f0e0fd 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3170,23 +3170,42 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, if (!test_opt(sb, QUOTA)) return -EINVAL; - /* Not journalling quota? */ - if ((!EXT4_SB(sb)->s_qf_names[USRQUOTA] && - !EXT4_SB(sb)->s_qf_names[GRPQUOTA]) || remount) + /* When remounting, no checks are needed and in fact, path is NULL */ + if (remount) return vfs_quota_on(sb, type, format_id, path, remount); + err = path_lookup(path, LOOKUP_FOLLOW, &nd); if (err) return err; + /* Quotafile not on the same filesystem? */ if (nd.path.mnt->mnt_sb != sb) { path_put(&nd.path); return -EXDEV; } - /* Quotafile not of fs root? */ - if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) - printk(KERN_WARNING - "EXT4-fs: Quota file not on filesystem root. " - "Journalled quota will not work.\n"); + /* Journaling quota? */ + if (EXT4_SB(sb)->s_qf_names[type]) { + /* Quotafile not of fs root? */ + if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) + printk(KERN_WARNING + "EXT4-fs: Quota file not on filesystem root. " + "Journaled quota will not work.\n"); + } + + /* + * When we journal data on quota file, we have to flush journal to see + * all updates to the file when we bypass pagecache... + */ + if (ext4_should_journal_data(nd.path.dentry->d_inode)) { + /* + * We don't need to lock updates but journal_flush() could + * otherwise be livelocked... + */ + jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); + jbd2_journal_flush(EXT4_SB(sb)->s_journal); + jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); + } + path_put(&nd.path); return vfs_quota_on(sb, type, format_id, path, remount); } -- cgit v1.2.3 From 2c8be6b222f76c332d9faeb00c047996d340632c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 13 May 2008 21:27:55 -0400 Subject: ext4: fix typos in messages and comments (journalled -> journaled) Cc: Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/ext4/super.c b/fs/ext4/super.c index cddf7f0e0fd..09d9359c805 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1166,7 +1166,7 @@ set_qf_name: sb_any_quota_suspended(sb)) && !sbi->s_qf_names[qtype]) { printk(KERN_ERR - "EXT4-fs: Cannot change journalled " + "EXT4-fs: Cannot change journaled " "quota options when quota turned on.\n"); return 0; } @@ -1206,7 +1206,7 @@ clear_qf_name: sb_any_quota_suspended(sb)) && sbi->s_qf_names[qtype]) { printk(KERN_ERR "EXT4-fs: Cannot change " - "journalled quota options when " + "journaled quota options when " "quota turned on.\n"); return 0; } @@ -1350,14 +1350,14 @@ set_qf_format: } if (!sbi->s_jquota_fmt) { - printk(KERN_ERR "EXT4-fs: journalled quota format " + printk(KERN_ERR "EXT4-fs: journaled quota format " "not specified.\n"); return 0; } } else { if (sbi->s_jquota_fmt) { - printk(KERN_ERR "EXT4-fs: journalled quota format " - "specified with no journalling " + printk(KERN_ERR "EXT4-fs: journaled quota format " + "specified with no journaling " "enabled.\n"); return 0; } @@ -1598,7 +1598,7 @@ static void ext4_orphan_cleanup (struct super_block * sb, int ret = ext4_quota_on_mount(sb, i); if (ret < 0) printk(KERN_ERR - "EXT4-fs: Cannot turn on journalled " + "EXT4-fs: Cannot turn on journaled " "quota: error %d\n", ret); } } @@ -3123,7 +3123,7 @@ static int ext4_release_dquot(struct dquot *dquot) static int ext4_mark_dquot_dirty(struct dquot *dquot) { - /* Are we journalling quotas? */ + /* Are we journaling quotas? */ if (EXT4_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || EXT4_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { dquot_mark_dquot_dirty(dquot); -- cgit v1.2.3 From 1930479c4b6bbcb6f164a5b3498e0d98329967f4 Mon Sep 17 00:00:00 2001 From: Valerie Clement Date: Tue, 13 May 2008 19:31:14 -0400 Subject: ext4: mballoc fix mb_normalize_request algorithm for 1KB block size filesystems In case of inode preallocation, the number of blocks to allocate depends on the file size and it is calculated in ext4_mb_normalize_request(). Each group in the filesystem is then checked to find one that can be used for allocation; this is done in ext4_mb_good_group(). When a file bigger than 4MB is created, the requested number of blocks to preallocate, calculated by ext4_mb_normalize_request is 4096. However for a filesystem with 1KB block size, the maximum size of the block buddies used by the multiblock allocator is 2048, so none of groups in the filesystem satisfies the search criteria in ext4_mb_good_group(). Scanning all the filesystem groups impacts performance. This was demonstrated by using a freshly created, 70GB, 1k block filesystem, with caches dropped write before the test via /proc/sys/vm/drop_caches, and with the filesystem mounted with nodelalloc and nodealloc,nomballoc. The time to write an 8 megabyte file using "dd if=/dev/zero of=/mnt/test/fo bs=8k count=1k conv=fsync" took 35.5091 seconds (236kB/s) with nodellaloc, and 0.233754 seconds (35.9 MB/s) with the nodelloc,nomballoc options. With a 1TB partition, it took several minutes to write 8MB! This patch modifies the algorithm in ext4_mb_normalize_group_request to calculate the number of blocks to allocate by taking into account the maximum size of free blocks chunks handled by the multiblock allocator. It has also been tested for filesystems with 2KB and 4KB block sizes to ensure that those cases don't regress. Reviewed-by: Aneesh Kumar K.V Signed-off-by: Valerie Clement Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/mballoc.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index b128bdc0f55..1d7fde99452 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2880,12 +2880,11 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, if (size < i_size_read(ac->ac_inode)) size = i_size_read(ac->ac_inode); - /* max available blocks in a free group */ - max = EXT4_BLOCKS_PER_GROUP(ac->ac_sb) - 1 - 1 - - EXT4_SB(ac->ac_sb)->s_itb_per_group; + /* max size of free chunks */ + max = 2 << bsbits; -#define NRL_CHECK_SIZE(req, size, max,bits) \ - (req <= (size) || max <= ((size) >> bits)) +#define NRL_CHECK_SIZE(req, size, max, chunk_size) \ + (req <= (size) || max <= (chunk_size)) /* first, try to predict filesize */ /* XXX: should this table be tunable? */ @@ -2904,16 +2903,16 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, size = 512 * 1024; } else if (size <= 1024 * 1024) { size = 1024 * 1024; - } else if (NRL_CHECK_SIZE(size, 4 * 1024 * 1024, max, bsbits)) { + } else if (NRL_CHECK_SIZE(size, 4 * 1024 * 1024, max, 2 * 1024)) { start_off = ((loff_t)ac->ac_o_ex.fe_logical >> - (20 - bsbits)) << 20; - size = 1024 * 1024; - } else if (NRL_CHECK_SIZE(size, 8 * 1024 * 1024, max, bsbits)) { + (21 - bsbits)) << 21; + size = 2 * 1024 * 1024; + } else if (NRL_CHECK_SIZE(size, 8 * 1024 * 1024, max, 4 * 1024)) { start_off = ((loff_t)ac->ac_o_ex.fe_logical >> (22 - bsbits)) << 22; size = 4 * 1024 * 1024; } else if (NRL_CHECK_SIZE(ac->ac_o_ex.fe_len, - (8<<20)>>bsbits, max, bsbits)) { + (8<<20)>>bsbits, max, 8 * 1024)) { start_off = ((loff_t)ac->ac_o_ex.fe_logical >> (23 - bsbits)) << 23; size = 8 * 1024 * 1024; -- cgit v1.2.3 From e10f7b551d2a79b113d5ce66b5dc9f3657035445 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 14 May 2008 10:21:33 -0700 Subject: clarify return value of cifs_convert_flags() cifs_convert_flags returns 0x20197 in the default case. It's not immediately evident where that number comes from, so change it to be an or'ed set of flags. The compiler will boil it down anyway. (Thanks to Guenter Kukkukk for clarifying the flags). Signed-off-by: Steve French --- fs/cifs/file.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 31a0a33b9d9..8636cec2642 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -75,7 +75,11 @@ static inline int cifs_convert_flags(unsigned int flags) return (GENERIC_READ | GENERIC_WRITE); } - return 0x20197; + return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | + FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA | + FILE_READ_DATA); + + } static inline int cifs_get_disposition(unsigned int flags) -- cgit v1.2.3 From 35fc37d5175091c36d034a28c057da0f9594ee7e Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 14 May 2008 10:22:03 -0700 Subject: add function to convert access flags to legacy open mode SMBLegacyOpen always opens a file as r/w. This could be problematic for files with ATTR_READONLY set. Have it interpret the access_mode into a sane open mode. Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 22 +++++++++++++++------- fs/cifs/inode.c | 3 +-- 2 files changed, 16 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 3c05c2de50e..9c04ad40455 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1166,6 +1166,20 @@ static __u16 convert_disposition(int disposition) return ofun; } +static int +access_flags_to_smbopen_mode(const int access_flags) +{ + int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE); + + if (masked_flags == GENERIC_READ) + return SMBOPEN_READ; + else if (masked_flags == GENERIC_WRITE) + return SMBOPEN_WRITE; + + /* just go for read/write */ + return SMBOPEN_READWRITE; +} + int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, const char *fileName, const int openDisposition, @@ -1207,13 +1221,7 @@ OldOpenRetry: pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); - /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */ - /* 0 = read - 1 = write - 2 = rw - 3 = execute - */ - pSMB->Mode = cpu_to_le16(2); + pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags)); pSMB->Mode |= cpu_to_le16(0x40); /* deny none */ /* set file as system file if special file such as fifo and server expecting SFU style and diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index fcbdbb6ad7b..2d53b436d51 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1502,8 +1502,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) int oplock = 0; rc = SMBLegacyOpen(xid, pTcon, full_path, - FILE_OPEN, - SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, + FILE_OPEN, GENERIC_WRITE, CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & -- cgit v1.2.3 From b32a09db4fb9a87246ba4e7726a979ac4709ad97 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 26 Feb 2008 09:57:11 -0600 Subject: add match_strlcpy() us it to make v9fs make uname and remotename parsing more robust match_strcpy() is a somewhat creepy function: the caller needs to make sure that the destination buffer is big enough, and when he screws up or forgets, match_strcpy() happily overruns the buffer. There's exactly one customer: v9fs_parse_options(). I believe it currently can't overflow its buffer, but that's not exactly obvious. The source string is a substing of the mount options. The kernel silently truncates those to PAGE_SIZE bytes, including the terminating zero. See compat_sys_mount() and do_mount(). The destination buffer is obtained from __getname(), which allocates from name_cachep, which is initialized by vfs_caches_init() for size PATH_MAX. We're safe as long as PATH_MAX <= PAGE_SIZE. PATH_MAX is 4096. As far as I know, the smallest PAGE_SIZE is also 4096. Here's a patch that makes the code a bit more obviously correct. It doesn't depend on PATH_MAX <= PAGE_SIZE. Signed-off-by: Markus Armbruster Cc: Latchesar Ionkov Cc: Jim Meyering Cc: "Randy.Dunlap" Signed-off-by: Andrew Morton Signed-off-by: Eric Van Hensbergen --- fs/9p/v9fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 9b0f0222e8b..e307fbd34fa 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -125,10 +125,10 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses) v9ses->afid = option; break; case Opt_uname: - match_strcpy(v9ses->uname, &args[0]); + match_strlcpy(v9ses->uname, &args[0], PATH_MAX); break; case Opt_remotename: - match_strcpy(v9ses->aname, &args[0]); + match_strlcpy(v9ses->aname, &args[0], PATH_MAX); break; case Opt_nodevmap: v9ses->nodev = 1; -- cgit v1.2.3 From ee443996a35c1e04f210cafd43d5a98d41e46085 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Wed, 5 Mar 2008 07:08:09 -0600 Subject: 9p: Documentation updates The kernel-doc comments of much of the 9p system have been in disarray since reorganization. This patch fixes those problems, adds additional documentation and a template book which collects the 9p information. Signed-off-by: Eric Van Hensbergen --- fs/9p/fid.h | 15 ++++++++++ fs/9p/v9fs.c | 8 ++++-- fs/9p/v9fs.h | 85 +++++++++++++++++++++++++++++++++++++++---------------- fs/9p/vfs_addr.c | 2 +- fs/9p/vfs_dir.c | 2 +- fs/9p/vfs_file.c | 11 +++---- fs/9p/vfs_inode.c | 50 +++++++++++++++++++++++--------- fs/9p/vfs_super.c | 1 + 8 files changed, 126 insertions(+), 48 deletions(-) (limited to 'fs') diff --git a/fs/9p/fid.h b/fs/9p/fid.h index 26e07df783b..c3bbd6af996 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h @@ -22,6 +22,21 @@ #include +/** + * struct v9fs_dentry - 9p private data stored in dentry d_fsdata + * @lock: protects the fidlist + * @fidlist: list of FIDs currently associated with this dentry + * + * This structure defines the 9p private data associated with + * a particular dentry. In particular, this private data is used + * to lookup which 9P FID handle should be used for a particular VFS + * operation. FID handles are associated with dentries instead of + * inodes in order to more closely map functionality to the Plan 9 + * expected behavior for FID reclaimation and tracking. + * + * See Also: Mapping FIDs to Linux VFS model in + * Design and Implementation of the Linux 9P File System documentation + */ struct v9fs_dentry { spinlock_t lock; /* protect fidlist */ struct list_head fidlist; diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index e307fbd34fa..79d310c0018 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -71,7 +71,6 @@ static match_table_t tokens = { /** * v9fs_parse_options - parse mount options into session structure - * @options: options string passed from mount * @v9ses: existing v9fs session information * */ @@ -256,9 +255,12 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) } /** - * v9fs_session_cancel - mark transport as disconnected - * and cancel all pending requests. + * v9fs_session_cancel - terminate a session + * @v9ses: session to terminate + * + * mark transport as disconnected and cancel all pending requests. */ + void v9fs_session_cancel(struct v9fs_session_info *v9ses) { P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses); p9_client_disconnect(v9ses->clnt); diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 7d3a1018db5..a7d56719299 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -21,18 +21,69 @@ * */ -/* - * Session structure provides information for an opened session - * - */ +/** + * enum p9_session_flags - option flags for each 9P session + * @V9FS_EXTENDED: whether or not to use 9P2000.u extensions + * @V9FS_ACCESS_SINGLE: only the mounting user can access the hierarchy + * @V9FS_ACCESS_USER: a new attach will be issued for every user (default) + * @V9FS_ACCESS_ANY: use a single attach for all users + * @V9FS_ACCESS_MASK: bit mask of different ACCESS options + * + * Session flags reflect options selected by users at mount time + */ +enum p9_session_flags { + V9FS_EXTENDED = 0x01, + V9FS_ACCESS_SINGLE = 0x02, + V9FS_ACCESS_USER = 0x04, + V9FS_ACCESS_ANY = 0x06, + V9FS_ACCESS_MASK = 0x06, +}; + +/* possible values of ->cache */ +/** + * enum p9_cache_modes - user specified cache preferences + * @CACHE_NONE: do not cache data, dentries, or directory contents (default) + * @CACHE_LOOSE: cache data, dentries, and directory contents w/no consistency + * + * eventually support loose, tight, time, session, default always none + */ + +enum p9_cache_modes { + CACHE_NONE, + CACHE_LOOSE, +}; + +/** + * struct v9fs_session_info - per-instance session information + * @flags: session options of type &p9_session_flags + * @nodev: set to 1 to disable device mapping + * @debug: debug level + * @afid: authentication handle + * @cache: cache mode of type &p9_cache_modes + * @options: copy of options string given by user + * @uname: string user name to mount hierarchy as + * @aname: mount specifier for remote hierarchy + * @maxdata: maximum data to be sent/recvd per protocol message + * @dfltuid: default numeric userid to mount hierarchy as + * @dfltgid: default numeric groupid to mount hierarchy as + * @uid: if %V9FS_ACCESS_SINGLE, the numeric uid which mounted the hierarchy + * @clnt: reference to 9P network client instantiated for this session + * @debugfs_dir: reference to debugfs_dir which can be used for add'l debug + * + * This structure holds state for each session instance established during + * a sys_mount() . + * + * Bugs: there seems to be a lot of state which could be condensed and/or + * removed. + */ struct v9fs_session_info { /* options */ - unsigned char flags; /* session flags */ - unsigned char nodev; /* set to 1 if no disable device mapping */ - unsigned short debug; /* debug level */ - unsigned int afid; /* authentication fid */ - unsigned int cache; /* cache mode */ + unsigned char flags; + unsigned char nodev; + unsigned short debug; + unsigned int afid; + unsigned int cache; char *options; /* copy of mount options */ char *uname; /* user name to mount as */ @@ -45,22 +96,6 @@ struct v9fs_session_info { struct dentry *debugfs_dir; }; -/* session flags */ -enum { - V9FS_EXTENDED = 0x01, /* 9P2000.u */ - V9FS_ACCESS_MASK = 0x06, /* access mask */ - V9FS_ACCESS_SINGLE = 0x02, /* only one user can access the files */ - V9FS_ACCESS_USER = 0x04, /* attache per user */ - V9FS_ACCESS_ANY = 0x06, /* use the same attach for all users */ -}; - -/* possible values of ->cache */ -/* eventually support loose, tight, time, session, default always none */ -enum { - CACHE_NONE, /* default */ - CACHE_LOOSE, /* no consistency */ -}; - extern struct dentry *v9fs_debugfs_root; struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *, diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index 6248f0e727a..97d3aed5798 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -43,7 +43,7 @@ /** * v9fs_vfs_readpage - read an entire page in from 9P * - * @file: file being read + * @filp: file being read * @page: structure to page * */ diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 0924d4477da..88e3787c6ea 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -60,7 +60,7 @@ static inline int dt_type(struct p9_stat *mistat) /** * v9fs_dir_readdir - read a directory - * @filep: opened file structure + * @filp: opened file structure * @dirent: directory structure ??? * @filldir: function to populate directory structure ??? * diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index a616fff8906..0d55affe37d 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -90,10 +90,11 @@ int v9fs_file_open(struct inode *inode, struct file *file) /** * v9fs_file_lock - lock a file (or directory) - * @inode: inode to be opened - * @file: file being opened + * @filp: file to be locked + * @cmd: lock command + * @fl: file lock structure * - * XXX - this looks like a local only lock, we should extend into 9P + * Bugs: this looks like a local only lock, we should extend into 9P * by using open exclusive */ @@ -118,7 +119,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) /** * v9fs_file_read - read from a file - * @filep: file pointer to read + * @filp: file pointer to read * @data: data buffer to read data into * @count: size of buffer * @offset: offset at which to read data @@ -142,7 +143,7 @@ v9fs_file_read(struct file *filp, char __user * data, size_t count, /** * v9fs_file_write - write to a file - * @filep: file pointer to write + * @filp: file pointer to write * @data: data buffer to write data from * @count: size of buffer * @offset: offset at which to write data diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 6a28842052e..40fa807bd92 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -129,6 +129,12 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) return res; } +/** + * v9fs_uflags2omode- convert posix open flags to plan 9 mode bits + * @uflags: flags to convert + * + */ + int v9fs_uflags2omode(int uflags) { int ret; @@ -312,6 +318,14 @@ error: } */ +/** + * v9fs_inode_from_fid - populate an inode by issuing a attribute request + * @v9ses: session information + * @fid: fid to issue attribute request for + * @sb: superblock on which to create inode + * + */ + static struct inode * v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, struct super_block *sb) @@ -384,9 +398,12 @@ v9fs_open_created(struct inode *inode, struct file *file) /** * v9fs_create - Create a file + * @v9ses: session information + * @dir: directory that dentry is being created in * @dentry: dentry that is being created * @perm: create permissions * @mode: open mode + * @extension: 9p2000.u extension string to support devices, etc. * */ static struct p9_fid * @@ -461,7 +478,7 @@ error: /** * v9fs_vfs_create - VFS hook to create files - * @inode: directory inode that is being created + * @dir: directory inode that is being created * @dentry: dentry that is being deleted * @mode: create permissions * @nd: path information @@ -519,7 +536,7 @@ error: /** * v9fs_vfs_mkdir - VFS mkdir hook to create a directory - * @inode: inode that is being unlinked + * @dir: inode that is being unlinked * @dentry: dentry that is being unlinked * @mode: mode for new directory * @@ -703,9 +720,9 @@ done: /** * v9fs_vfs_getattr - retrieve file metadata - * @mnt - mount information - * @dentry - file to get attributes on - * @stat - metadata structure to populate + * @mnt: mount information + * @dentry: file to get attributes on + * @stat: metadata structure to populate * */ @@ -928,7 +945,7 @@ done: /** * v9fs_vfs_readlink - read a symlink's location * @dentry: dentry for symlink - * @buf: buffer to load symlink location into + * @buffer: buffer to load symlink location into * @buflen: length of buffer * */ @@ -996,10 +1013,12 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) * v9fs_vfs_put_link - release a symlink path * @dentry: dentry for symlink * @nd: nameidata + * @p: unused * */ -static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) +static void +v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) { char *s = nd_get_link(nd); @@ -1008,6 +1027,15 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void __putname(s); } +/** + * v9fs_vfs_mkspecial - create a special file + * @dir: inode to create special file in + * @dentry: dentry to create + * @mode: mode to create special file + * @extension: 9p2000.u format extension string representing special file + * + */ + static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, int mode, const char *extension) { @@ -1037,7 +1065,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, * @dentry: dentry for symlink * @symname: symlink data * - * See 9P2000.u RFC for more information + * See Also: 9P2000.u RFC for more information * */ @@ -1058,10 +1086,6 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) * */ -/* XXX - lots of code dup'd from symlink and creates, - * figure out a better reuse strategy - */ - static int v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) @@ -1098,7 +1122,7 @@ clunk_fid: * @dir: inode destination for new link * @dentry: dentry for file * @mode: mode for creation - * @dev_t: device associated with special file + * @rdev: device associated with special file * */ diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index a452ac67fc9..ba10f172626 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -75,6 +75,7 @@ static int v9fs_set_super(struct super_block *s, void *data) * v9fs_fill_super - populate superblock with info * @sb: superblock * @v9ses: session information + * @flags: flags propagated from v9fs_get_sb() * */ -- cgit v1.2.3 From ab31267dfeddf80b2e483f077c8b03905993722b Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Thu, 6 Mar 2008 17:10:28 -0600 Subject: fs/9p/v9fs.c (v9fs_parse_options): Handle kstrdup and match_strdup failure. Now that this function can fail, return an int, diagnose other option-parsing failures, and adjust the sole caller: (v9fs_session_init): Handle kstrdup failure. Propagate any new v9fs_parse_options failure "up". Signed-off-by: Jim Meyering Cc: Ron Minnich Cc: Latchesar Ionkov Signed-off-by: Andrew Morton Acked-by: Eric Van Hensbergen --- fs/9p/v9fs.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 79d310c0018..5c1ccaf0416 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -73,16 +73,17 @@ static match_table_t tokens = { * v9fs_parse_options - parse mount options into session structure * @v9ses: existing v9fs session information * + * Return 0 upon success, -ERRNO upon failure. */ -static void v9fs_parse_options(struct v9fs_session_info *v9ses) +static int v9fs_parse_options(struct v9fs_session_info *v9ses) { char *options; substring_t args[MAX_OPT_ARGS]; char *p; int option = 0; char *s, *e; - int ret; + int ret = 0; /* setup defaults */ v9ses->afid = ~0; @@ -90,19 +91,26 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses) v9ses->cache = 0; if (!v9ses->options) - return; + return 0; options = kstrdup(v9ses->options, GFP_KERNEL); + if (!options) { + P9_DPRINTK(P9_DEBUG_ERROR, + "failed to allocate copy of option string\n"); + return -ENOMEM; + } + while ((p = strsep(&options, ",")) != NULL) { int token; if (!*p) continue; token = match_token(p, tokens, args); if (token < Opt_uname) { - ret = match_int(&args[0], &option); - if (ret < 0) { + int r = match_int(&args[0], &option); + if (r < 0) { P9_DPRINTK(P9_DEBUG_ERROR, "integer field, but no integer?\n"); + ret = r; continue; } } @@ -138,6 +146,13 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses) case Opt_access: s = match_strdup(&args[0]); + if (!s) { + P9_DPRINTK(P9_DEBUG_ERROR, + "failed to allocate copy" + " of option argument\n"); + ret = -ENOMEM; + break; + } v9ses->flags &= ~V9FS_ACCESS_MASK; if (strcmp(s, "user") == 0) v9ses->flags |= V9FS_ACCESS_USER; @@ -157,6 +172,7 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses) } } kfree(options); + return ret; } /** @@ -172,6 +188,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, { int retval = -EINVAL; struct p9_fid *fid; + int rc; v9ses->uname = __getname(); if (!v9ses->uname) @@ -190,7 +207,18 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, v9ses->dfltuid = V9FS_DEFUID; v9ses->dfltgid = V9FS_DEFGID; v9ses->options = kstrdup(data, GFP_KERNEL); - v9fs_parse_options(v9ses); + if (!v9ses->options) { + P9_DPRINTK(P9_DEBUG_ERROR, + "failed to allocate copy of option string\n"); + retval = -ENOMEM; + goto error; + } + + rc = v9fs_parse_options(v9ses); + if (rc < 0) { + retval = rc; + goto error; + } v9ses->clnt = p9_client_create(dev_name, v9ses->options); -- cgit v1.2.3 From 887b3ece65be7b643dfdae0d433c91a26a3f437d Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Thu, 8 May 2008 20:26:37 -0500 Subject: 9p: fix error path during early mount There was some cleanup issues during early mount which would trigger a kernel bug for certain types of failure. This patch reorganizes the cleanup to get rid of the bad behavior. This also merges the 9pnet and 9pnet_fd modules for the purpose of configuration and initialization. Keeping the fd transport separate from the core 9pnet code seemed like a good idea at the time, but in practice has caused more harm and confusion than good. Signed-off-by: Eric Van Hensbergen --- fs/9p/v9fs.c | 13 +++++++------ fs/9p/vfs_super.c | 34 ++++++++++++++++------------------ 2 files changed, 23 insertions(+), 24 deletions(-) (limited to 'fs') diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 5c1ccaf0416..047c791427a 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -206,12 +206,14 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, v9ses->uid = ~0; v9ses->dfltuid = V9FS_DEFUID; v9ses->dfltgid = V9FS_DEFGID; - v9ses->options = kstrdup(data, GFP_KERNEL); - if (!v9ses->options) { - P9_DPRINTK(P9_DEBUG_ERROR, + if (data) { + v9ses->options = kstrdup(data, GFP_KERNEL); + if (!v9ses->options) { + P9_DPRINTK(P9_DEBUG_ERROR, "failed to allocate copy of option string\n"); - retval = -ENOMEM; - goto error; + retval = -ENOMEM; + goto error; + } } rc = v9fs_parse_options(v9ses); @@ -260,7 +262,6 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, return fid; error: - v9fs_session_close(v9ses); return ERR_PTR(retval); } diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index ba10f172626..bf59c396049 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -128,29 +128,26 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, fid = v9fs_session_init(v9ses, dev_name, data); if (IS_ERR(fid)) { retval = PTR_ERR(fid); - fid = NULL; - kfree(v9ses); - v9ses = NULL; - goto error; + goto close_session; } st = p9_client_stat(fid); if (IS_ERR(st)) { retval = PTR_ERR(st); - goto error; + goto clunk_fid; } sb = sget(fs_type, NULL, v9fs_set_super, v9ses); if (IS_ERR(sb)) { retval = PTR_ERR(sb); - goto error; + goto free_stat; } v9fs_fill_super(sb, v9ses, flags); inode = v9fs_get_inode(sb, S_IFDIR | mode); if (IS_ERR(inode)) { retval = PTR_ERR(inode); - goto error; + goto release_sb; } inode->i_uid = uid; @@ -159,7 +156,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, root = d_alloc_root(inode); if (!root) { retval = -ENOMEM; - goto error; + goto release_sb; } sb->s_root = root; @@ -170,21 +167,22 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, return simple_set_mnt(mnt, sb); -error: - kfree(st); - if (fid) - p9_client_clunk(fid); - - if (v9ses) { - v9fs_session_close(v9ses); - kfree(v9ses); - } - +release_sb: if (sb) { up_write(&sb->s_umount); deactivate_super(sb); } +free_stat: + kfree(st); + +clunk_fid: + p9_client_clunk(fid); + +close_session: + v9fs_session_close(v9ses); + kfree(v9ses); + return retval; } -- cgit v1.2.3 From 646dd539878a194bc14b104621c0b2b33587e40f Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 15 May 2008 01:50:56 +0000 Subject: [CIFS] Fix paths when share is in DFS to include proper prefix Some versions of Samba (3.2-pre e.g.) are stricter about checking to make sure that paths in DFS name spaces are sent in the form \\server\share\dir\subdir ... instead of \dir\subdir Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 3 --- fs/cifs/connect.c | 26 +++------------------ fs/cifs/dir.c | 28 ++++++++++++++++++----- fs/cifs/inode.c | 65 +++++++---------------------------------------------- fs/cifs/link.c | 42 +++------------------------------- 5 files changed, 37 insertions(+), 127 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 08248e85b78..845b18e1abe 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -150,9 +150,6 @@ extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, unsigned int *number_of_UNC_in_array, const struct nls_table *nls_codepage, int remap); -extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, - const char *old_path, - const struct nls_table *nls_codepage, int remap); extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, const struct nls_table *nls_codepage, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 7c2e5ea0330..d5747e30f1c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1418,27 +1418,6 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) return NULL; } -int -connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, - const char *old_path, const struct nls_table *nls_codepage, - int remap) -{ - struct dfs_info3_param *referrals = NULL; - unsigned int num_referrals; - int rc = 0; - - rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage, - &num_referrals, &referrals, remap); - - /* BB Add in code to: if valid refrl, if not ip address contact - the helper that resolves tcp names, mount to it, try to - tcon to it unmount it if fail */ - - kfree(referrals); - - return rc; -} - int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, const struct nls_table *nls_codepage, unsigned int *pnum_referrals, @@ -2161,10 +2140,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if ((strchr(volume_info.UNC + 3, '\\') == NULL) && (strchr(volume_info.UNC + 3, '/') == NULL)) { - rc = connect_to_dfs_path(xid, pSesInfo, +/* rc = connect_to_dfs_path(xid, pSesInfo, "", cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + CIFS_MOUNT_MAP_SPECIAL_CHR);*/ + cFYI(1, ("DFS root not supported")); rc = -ENODEV; goto out; } else { diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e4e0078a052..05afe33ea64 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -49,18 +49,25 @@ build_path_from_dentry(struct dentry *direntry) struct dentry *temp; int namelen; int pplen; + int dfsplen; char *full_path; char dirsep; + struct cifs_sb_info *cifs_sb; if (direntry == NULL) return NULL; /* not much we can do if dentry is freed and we need to reopen the file after it was closed implicitly when the server crashed */ - dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); - pplen = CIFS_SB(direntry->d_sb)->prepathlen; + cifs_sb = CIFS_SB(direntry->d_sb); + dirsep = CIFS_DIR_SEP(cifs_sb); + pplen = cifs_sb->prepathlen; + if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS)) + dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1); + else + dfsplen = 0; cifs_bp_rename_retry: - namelen = pplen; + namelen = pplen + dfsplen; for (temp = direntry; !IS_ROOT(temp);) { namelen += (1 + temp->d_name.len); temp = temp->d_parent; @@ -91,7 +98,7 @@ cifs_bp_rename_retry: return NULL; } } - if (namelen != pplen) { + if (namelen != pplen + dfsplen) { cERROR(1, ("did not end path lookup where expected namelen is %d", namelen)); @@ -107,7 +114,18 @@ cifs_bp_rename_retry: since the '\' is a valid posix character so we can not switch those safely to '/' if any are found in the middle of the prepath */ /* BB test paths to Windows with '/' in the midst of prepath */ - strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen); + + if (dfsplen) { + strncpy(full_path, cifs_sb->tcon->treeName, dfsplen); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { + int i; + for (i = 0; i < dfsplen; i++) { + if (full_path[i] == '\\') + full_path[i] = '/'; + } + } + } + strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen); return full_path; } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 2d53b436d51..9d9b56a9c08 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -161,52 +161,18 @@ static void cifs_unix_info_to_inode(struct inode *inode, spin_unlock(&inode->i_lock); } -static const unsigned char *cifs_get_search_path(struct cifs_sb_info *cifs_sb, - const char *search_path) -{ - int tree_len; - int path_len; - int i; - char *tmp_path; - struct cifsTconInfo *pTcon = cifs_sb->tcon; - - if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS)) - return search_path; - - /* use full path name for working with DFS */ - tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1); - path_len = strnlen(search_path, MAX_PATHCONF); - - tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL); - if (tmp_path == NULL) - return search_path; - - strncpy(tmp_path, pTcon->treeName, tree_len); - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) - for (i = 0; i < tree_len; i++) { - if (tmp_path[i] == '\\') - tmp_path[i] = '/'; - } - strncpy(tmp_path+tree_len, search_path, path_len); - tmp_path[tree_len+path_len] = 0; - return tmp_path; -} - int cifs_get_inode_info_unix(struct inode **pinode, - const unsigned char *search_path, struct super_block *sb, int xid) + const unsigned char *full_path, struct super_block *sb, int xid) { int rc = 0; FILE_UNIX_BASIC_INFO findData; struct cifsTconInfo *pTcon; struct inode *inode; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - const unsigned char *full_path; bool is_dfs_referral = false; pTcon = cifs_sb->tcon; - cFYI(1, ("Getting info on %s", search_path)); - - full_path = cifs_get_search_path(cifs_sb, search_path); + cFYI(1, ("Getting info on %s", full_path)); try_again_CIFSSMBUnixQPathInfo: /* could have done a find first instead but this returns more info */ @@ -218,10 +184,6 @@ try_again_CIFSSMBUnixQPathInfo: if (rc) { if (rc == -EREMOTE && !is_dfs_referral) { is_dfs_referral = true; - if (full_path != search_path) { - kfree(full_path); - full_path = search_path; - } goto try_again_CIFSSMBUnixQPathInfo; } goto cgiiu_exit; @@ -271,8 +233,6 @@ try_again_CIFSSMBUnixQPathInfo: cifs_set_ops(inode, is_dfs_referral); } cgiiu_exit: - if (full_path != search_path) - kfree(full_path); return rc; } @@ -380,20 +340,19 @@ static int get_sfu_mode(struct inode *inode, } int cifs_get_inode_info(struct inode **pinode, - const unsigned char *search_path, FILE_ALL_INFO *pfindData, + const unsigned char *full_path, FILE_ALL_INFO *pfindData, struct super_block *sb, int xid, const __u16 *pfid) { int rc = 0; struct cifsTconInfo *pTcon; struct inode *inode; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - const unsigned char *full_path = NULL; char *buf = NULL; bool adjustTZ = false; bool is_dfs_referral = false; pTcon = cifs_sb->tcon; - cFYI(1, ("Getting info on %s", search_path)); + cFYI(1, ("Getting info on %s", full_path)); if ((pfindData == NULL) && (*pinode != NULL)) { if (CIFS_I(*pinode)->clientCanCacheRead) { @@ -409,8 +368,6 @@ int cifs_get_inode_info(struct inode **pinode, return -ENOMEM; pfindData = (FILE_ALL_INFO *)buf; - full_path = cifs_get_search_path(cifs_sb, search_path); - try_again_CIFSSMBQPathInfo: /* could do find first instead but this returns more info */ rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, @@ -432,10 +389,6 @@ try_again_CIFSSMBQPathInfo: if (rc) { if (rc == -EREMOTE && !is_dfs_referral) { is_dfs_referral = true; - if (full_path != search_path) { - kfree(full_path); - full_path = search_path; - } goto try_again_CIFSSMBQPathInfo; } goto cgii_exit; @@ -470,7 +423,7 @@ try_again_CIFSSMBQPathInfo: __u64 inode_num; rc1 = CIFSGetSrvInodeNumber(xid, pTcon, - search_path, &inode_num, + full_path, &inode_num, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -539,7 +492,7 @@ try_again_CIFSSMBQPathInfo: (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile), - search_path, + full_path, cifs_sb, xid)) cFYI(1, ("Unrecognized sfu inode type")); @@ -582,12 +535,12 @@ try_again_CIFSSMBQPathInfo: /* fill in 0777 bits from ACL */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { cFYI(1, ("Getting mode bits from ACL")); - acl_to_uid_mode(inode, search_path, pfid); + acl_to_uid_mode(inode, full_path, pfid); } #endif if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { /* fill in remaining high mode bits e.g. SUID, VTX */ - get_sfu_mode(inode, search_path, cifs_sb, xid); + get_sfu_mode(inode, full_path, cifs_sb, xid); } else if (atomic_read(&cifsInfo->inUse) == 0) { inode->i_uid = cifs_sb->mnt_uid; inode->i_gid = cifs_sb->mnt_gid; @@ -599,8 +552,6 @@ try_again_CIFSSMBQPathInfo: cifs_set_ops(inode, is_dfs_referral); } cgii_exit: - if (full_path != search_path) - kfree(full_path); kfree(buf); return rc; } diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 1c2c3ce5020..316f9830ce3 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -295,45 +295,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) cFYI(1, ("Error closing junction point " "(open for ioctl)")); } - /* BB unwind this long, nested function, or remove BB */ - if (rc == -EIO) { - /* Query if DFS Junction */ - unsigned int num_referrals = 0; - struct dfs_info3_param *refs = NULL; - tmp_path = - kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1, - GFP_KERNEL); - if (tmp_path) { - strncpy(tmp_path, pTcon->treeName, - MAX_TREE_SIZE); - strncat(tmp_path, full_path, - MAX_PATHCONF); - rc = get_dfs_path(xid, pTcon->ses, - tmp_path, - cifs_sb->local_nls, - &num_referrals, &refs, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - cFYI(1, ("Get DFS for %s rc = %d ", - tmp_path, rc)); - if ((num_referrals == 0) && (rc == 0)) - rc = -EACCES; - else { - cFYI(1, ("num referral: %d", - num_referrals)); - if (refs && refs->path_name) { - strncpy(tmpbuffer, - refs->path_name, - len-1); - } - } - kfree(refs); - kfree(tmp_path); -} - /* BB add code like else decode referrals - then memcpy to tmpbuffer and free referrals - string array BB */ - } + /* If it is a DFS junction earlier we would have gotten + PATH_NOT_COVERED returned from server so we do + not need to request the DFS info here */ } } /* BB Anything else to do to handle recursive links? */ -- cgit v1.2.3 From 772279c5f1dceb58d451dca94b557fd89b1ce890 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 14 May 2008 16:05:41 -0700 Subject: jbd: need to hold j_state_lock to updates to transaction t_state to T_COMMIT Updating the current transaction's t_state is protected by j_state_lock. We need to do the same when updating the t_state to T_COMMIT. Signed-off-by: Mingming Cao Acked-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd/commit.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index cd931ef1f00..5a8ca61498c 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -470,7 +470,9 @@ void journal_commit_transaction(journal_t *journal) * transaction! Now comes the tricky part: we need to write out * metadata. Loop over the transaction's entire buffer list: */ + spin_lock(&journal->j_state_lock); commit_transaction->t_state = T_COMMIT; + spin_unlock(&journal->j_state_lock); J_ASSERT(commit_transaction->t_nr_buffers <= commit_transaction->t_outstanding_credits); -- cgit v1.2.3 From 7e01c8e5420b6c7f9d85d34c15d8c7a15c9fc720 Mon Sep 17 00:00:00 2001 From: Tiger Yang Date: Wed, 14 May 2008 16:05:47 -0700 Subject: ext3/4: fix uninitialized bs in ext3/4_xattr_set_handle() This fix the uninitialized bs when we try to replace a xattr entry in ibody with the new value which require more than free space. This situation only happens we format ext3/4 with inode size more than 128 and we have put xattr entries both in ibody and block. The consequences about this bug is we will lost the xattr block which pointed by i_file_acl with all xattr entires in it. We will alloc a new xattr block and put that large value entry in it. The old xattr block will become orphan block. Signed-off-by: Tiger Yang Cc: Cc: Andreas Gruenbacher Acked-by: Andreas Dilger Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/xattr.c | 5 +++++ fs/ext4/xattr.c | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'fs') diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index d4a4f0e9ff6..175414ac221 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -1000,6 +1000,11 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, i.value = NULL; error = ext3_xattr_block_set(handle, inode, &i, &bs); } else if (error == -ENOSPC) { + if (EXT3_I(inode)->i_file_acl && !bs.s.base) { + error = ext3_xattr_block_find(inode, &i, &bs); + if (error) + goto cleanup; + } error = ext3_xattr_block_set(handle, inode, &i, &bs); if (error) goto cleanup; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 3fbc2c6c3d0..ff08633f398 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -1009,6 +1009,11 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, i.value = NULL; error = ext4_xattr_block_set(handle, inode, &i, &bs); } else if (error == -ENOSPC) { + if (EXT4_I(inode)->i_file_acl && !bs.s.base) { + error = ext4_xattr_block_find(inode, &i, &bs); + if (error) + goto cleanup; + } error = ext4_xattr_block_set(handle, inode, &i, &bs); if (error) goto cleanup; -- cgit v1.2.3 From 0599ad53fee2d084f9ba26247d7452f06a40d298 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 14 May 2008 22:34:16 -0700 Subject: sysfs: remove error messages for -EEXIST case It is possible that the entry in sysfs already exists, one case of this is when a network device is renamed to bonding_masters. Anyway, in this case the proper error path is for device_rename to return an error code, not to generate bogus backtrace and errors. Also, to avoid possible races, the create link should be done before the remove link. This makes a device rename atomic operation like other renames. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller --- fs/sysfs/dir.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index a1c3a1fab7f..8c0e4b92574 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -419,12 +419,8 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, */ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { - if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) { - printk(KERN_WARNING "sysfs: duplicate filename '%s' " - "can not be created\n", sd->s_name); - WARN_ON(1); + if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) return -EEXIST; - } sd->s_parent = sysfs_get(acxt->parent_sd); -- cgit v1.2.3 From c32916374b2b4f4d2b7ccdb357fe7989f3b407a6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 15 May 2008 05:41:54 +0000 Subject: [CIFS] suppress duplicate warning fs/cifs/dir.c: In function 'cifs_ci_compare': fs/cifs/dir.c:582: warning: passing argument 1 of 'memcpy' discards qualifiers from pointer target type Signed-off-by: Andrew Morton Signed-off-by: Steve French --- fs/cifs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 05afe33ea64..f0b5b5f3dd2 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -608,7 +608,7 @@ static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, * case take precedence. If a is not a negative dentry, this * should have no side effects */ - memcpy(a->name, b->name, a->len); + memcpy((void *)a->name, b->name, a->len); return 0; } return 1; -- cgit v1.2.3 From f9ddcca4cf7d95238beb295484d1de7c0bf490dd Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 15 May 2008 05:51:55 +0000 Subject: [CIFS] BKL-removal: convert CIFS over to unlocked_ioctl cifs_ioctl doesn't seem to need the BKL for anything, so convert it over to use unlocked_ioctl. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 10 +++++----- fs/cifs/cifsfs.h | 3 +-- fs/cifs/ioctl.c | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 427a7c69589..b6436b888cf 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -657,7 +657,7 @@ const struct file_operations cifs_file_ops = { .splice_read = generic_file_splice_read, .llseek = cifs_llseek, #ifdef CONFIG_CIFS_POSIX - .ioctl = cifs_ioctl, + .unlocked_ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ #ifdef CONFIG_CIFS_EXPERIMENTAL @@ -677,7 +677,7 @@ const struct file_operations cifs_file_direct_ops = { .flush = cifs_flush, .splice_read = generic_file_splice_read, #ifdef CONFIG_CIFS_POSIX - .ioctl = cifs_ioctl, + .unlocked_ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ .llseek = cifs_llseek, #ifdef CONFIG_CIFS_EXPERIMENTAL @@ -697,7 +697,7 @@ const struct file_operations cifs_file_nobrl_ops = { .splice_read = generic_file_splice_read, .llseek = cifs_llseek, #ifdef CONFIG_CIFS_POSIX - .ioctl = cifs_ioctl, + .unlocked_ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ #ifdef CONFIG_CIFS_EXPERIMENTAL @@ -716,7 +716,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = { .flush = cifs_flush, .splice_read = generic_file_splice_read, #ifdef CONFIG_CIFS_POSIX - .ioctl = cifs_ioctl, + .unlocked_ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ .llseek = cifs_llseek, #ifdef CONFIG_CIFS_EXPERIMENTAL @@ -731,7 +731,7 @@ const struct file_operations cifs_dir_ops = { #ifdef CONFIG_CIFS_EXPERIMENTAL .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ - .ioctl = cifs_ioctl, + .unlocked_ioctl = cifs_ioctl, }; static void diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index cd1301a09b3..25a6cbd1552 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -95,8 +95,7 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *, size_t, int); extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); -extern int cifs_ioctl(struct inode *inode, struct file *filep, - unsigned int command, unsigned long arg); +extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); #ifdef CONFIG_CIFS_EXPERIMENTAL extern const struct export_operations cifs_export_ops; diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 5c792df13d6..0088a5b5256 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -30,9 +30,9 @@ #define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2) -int cifs_ioctl(struct inode *inode, struct file *filep, - unsigned int command, unsigned long arg) +long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) { + struct inode *inode = filep->f_dentry->d_inode; int rc = -ENOTTY; /* strange error - but the precedent */ int xid; struct cifs_sb_info *cifs_sb; -- cgit v1.2.3 From c2cf07d591ef7bc25c220249822d9bdf0f44c75c Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 15 May 2008 06:20:02 +0000 Subject: [CIFS] Finishup DFS code Fixup GetDFSRefer to prepare for cleanup of SMB response processing Fix build warning in link.c Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 4 +- fs/cifs/cifssmb.c | 169 ++++++++++++++++++++++++---------------------------- fs/cifs/connect.c | 3 +- fs/cifs/link.c | 1 - 4 files changed, 80 insertions(+), 97 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 845b18e1abe..b9f5e935f82 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -146,8 +146,8 @@ extern int CIFSSMBUnixQPathInfo(const int xid, extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, const unsigned char *searchName, - unsigned char **targetUNCs, - unsigned int *number_of_UNC_in_array, + struct dfs_info3_param **target_nodes, + unsigned int *number_of_nodes_in_array, const struct nls_table *nls_codepage, int remap); extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 9c04ad40455..fc297383cb0 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3870,8 +3870,8 @@ GetInodeNumOut: int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, const unsigned char *searchName, - unsigned char **targetUNCs, - unsigned int *number_of_UNC_in_array, + struct dfs_info3_param **target_nodes, + unsigned int *num_of_nodes, const struct nls_table *nls_codepage, int remap) { /* TRANS2_GET_DFS_REFERRAL */ @@ -3884,8 +3884,8 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, unsigned int i; char *temp; __u16 params, byte_count; - *number_of_UNC_in_array = 0; - *targetUNCs = NULL; + *num_of_nodes = 0; + *target_nodes = NULL; cFYI(1, ("In GetDFSRefer the path %s", searchName)); if (ses == NULL) @@ -3955,99 +3955,84 @@ getDFSRetry: (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cFYI(1, ("Send error in GetDFSRefer = %d", rc)); - } else { /* decode response */ -/* BB Add logic to parse referrals here */ - rc = validate_t2((struct smb_t2_rsp *)pSMBr); - - /* BB Also check if enough total bytes returned? */ - if (rc || (pSMBr->ByteCount < 17)) - rc = -EIO; /* bad smb */ - else { - __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); - __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount); - - cFYI(1, - ("Decoding GetDFSRefer response BCC: %d Offset %d", - pSMBr->ByteCount, data_offset)); - referrals = - (struct dfs_referral_level_3 *) - (8 /* sizeof start of data block */ + - data_offset + - (char *) &pSMBr->hdr.Protocol); - cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n" - "for referral one refer size: 0x%x srv " - "type: 0x%x refer flags: 0x%x ttl: 0x%x", - le16_to_cpu(pSMBr->NumberOfReferrals), - le16_to_cpu(pSMBr->DFSFlags), - le16_to_cpu(referrals->ReferralSize), - le16_to_cpu(referrals->ServerType), - le16_to_cpu(referrals->ReferralFlags), - le16_to_cpu(referrals->TimeToLive))); - /* BB This field is actually two bytes in from start of - data block so we could do safety check that DataBlock - begins at address of pSMBr->NumberOfReferrals */ - *number_of_UNC_in_array = - le16_to_cpu(pSMBr->NumberOfReferrals); - - /* BB Fix below so can return more than one referral */ - if (*number_of_UNC_in_array > 1) - *number_of_UNC_in_array = 1; - - /* get the length of the strings describing refs */ - name_len = 0; - for (i = 0; i < *number_of_UNC_in_array; i++) { - /* make sure that DfsPathOffset not past end */ - __u16 offset = - le16_to_cpu(referrals->DfsPathOffset); - if (offset > data_count) { - /* if invalid referral, stop here and do - not try to copy any more */ - *number_of_UNC_in_array = i; - break; - } - temp = ((char *)referrals) + offset; + goto GetDFSRefExit; + } + rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len += UniStrnlen((wchar_t *)temp, - data_count); - } else { - name_len += strnlen(temp, data_count); - } - referrals++; - /* BB add check that referral pointer does - not fall off end PDU */ - } - /* BB add check for name_len bigger than bcc */ - *targetUNCs = - kmalloc(name_len+1+(*number_of_UNC_in_array), - GFP_KERNEL); - if (*targetUNCs == NULL) { - rc = -ENOMEM; - goto GetDFSRefExit; + /* BB Also check if enough total bytes returned? */ + if (rc || (pSMBr->ByteCount < 17)) + rc = -EIO; /* bad smb */ + else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount); + + cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d", + pSMBr->ByteCount, data_offset)); + referrals = + (struct dfs_referral_level_3 *) + (8 /* sizeof start of data block */ + + data_offset + + (char *) &pSMBr->hdr.Protocol); + cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n" + "for referral one refer size: 0x%x srv " + "type: 0x%x refer flags: 0x%x ttl: 0x%x", + le16_to_cpu(pSMBr->NumberOfReferrals), + le16_to_cpu(pSMBr->DFSFlags), + le16_to_cpu(referrals->ReferralSize), + le16_to_cpu(referrals->ServerType), + le16_to_cpu(referrals->ReferralFlags), + le16_to_cpu(referrals->TimeToLive))); + /* BB This field is actually two bytes in from start of + data block so we could do safety check that DataBlock + begins at address of pSMBr->NumberOfReferrals */ + *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals); + + /* BB Fix below so can return more than one referral */ + if (*num_of_nodes > 1) + *num_of_nodes = 1; + + /* get the length of the strings describing refs */ + name_len = 0; + for (i = 0; i < *num_of_nodes; i++) { + /* make sure that DfsPathOffset not past end */ + __u16 offset = le16_to_cpu(referrals->DfsPathOffset); + if (offset > data_count) { + /* if invalid referral, stop here and do + not try to copy any more */ + *num_of_nodes = i; + break; } - /* copy the ref strings */ - referrals = (struct dfs_referral_level_3 *) - (8 /* sizeof data hdr */ + data_offset + - (char *) &pSMBr->hdr.Protocol); - - for (i = 0; i < *number_of_UNC_in_array; i++) { - temp = ((char *)referrals) + - le16_to_cpu(referrals->DfsPathOffset); - if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { - cifs_strfromUCS_le(*targetUNCs, - (__le16 *) temp, - name_len, - nls_codepage); - } else { - strncpy(*targetUNCs, temp, name_len); - } - /* BB update target_uncs pointers */ - referrals++; + temp = ((char *)referrals) + offset; + + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len += UniStrnlen((wchar_t *)temp, + data_count); + } else { + name_len += strnlen(temp, data_count); } - temp = *targetUNCs; - temp[name_len] = 0; + referrals++; + /* BB add check that referral pointer does + not fall off end PDU */ + } + /* BB add check for name_len bigger than bcc */ + *target_nodes = + kmalloc(name_len+1+(*num_of_nodes), + GFP_KERNEL); + if (*target_nodes == NULL) { + rc = -ENOMEM; + goto GetDFSRefExit; } + referrals = (struct dfs_referral_level_3 *) + (8 /* sizeof data hdr */ + data_offset + + (char *) &pSMBr->hdr.Protocol); + + for (i = 0; i < *num_of_nodes; i++) { + temp = ((char *)referrals) + + le16_to_cpu(referrals->DfsPathOffset); + /* BB update target_uncs pointers */ + referrals++; + } } GetDFSRefExit: if (pSMB) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d5747e30f1c..c397fcfd9f1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1425,7 +1425,6 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, { char *temp_unc; int rc = 0; - unsigned char *targetUNCs; *pnum_referrals = 0; *preferrals = NULL; @@ -1448,7 +1447,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, kfree(temp_unc); } if (rc == 0) - rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs, + rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, pnum_referrals, nls_codepage, remap); /* BB map targetUNCs to dfs_info3 structures, here or in CIFSGetDFSRefer BB */ diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 316f9830ce3..63f644000ce 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -234,7 +234,6 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; - char *tmp_path = NULL; char *tmpbuffer; int len; __u16 fid; -- cgit v1.2.3 From 95b1cb90b79896c4bf5ea484bee2b41d7d293f43 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 15 May 2008 16:44:38 +0000 Subject: [CIFS] enable parsing for transport encryption mount parm Samba now supports transport encryption on particular exports (mounted tree ids can be encrypted for servers which support the unix extensions). This adds parsing support to cifs mount option parsing for this. Signed-off-by: Steve French --- fs/cifs/README | 5 +++++ fs/cifs/cifsglob.h | 1 + fs/cifs/connect.c | 25 +++++++++++++++++-------- 3 files changed, 23 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/cifs/README b/fs/cifs/README index 621aa1a8597..2bd6fe556f8 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -483,6 +483,11 @@ A partial list of the supported mount options follows: sign Must use packet signing (helps avoid unwanted data modification by intermediate systems in the route). Note that signing does not work with lanman or plaintext authentication. + seal Must seal (encrypt) all data on this mounted share before + sending on the network. Requires support for Unix Extensions. + Note that this differs from the sign mount option in that it + causes encryption of data sent over this mounted share but other + shares mounted to the same server are unaffected. sec Security mode. Allowed values are: none attempt to connection as a null user (no name) krb5 Use Kerberos version 5 authentication diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b7d9f698e63..08914053242 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -281,6 +281,7 @@ struct cifsTconInfo { bool ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */ bool retry:1; bool nocase:1; + bool seal:1; /* transport encryption for this mounted share */ bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol for this mount even if server would support */ /* BB add field for back pointer to sb struct(s)? */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c397fcfd9f1..023434f72c1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -60,7 +60,7 @@ struct smb_vol { char *domainname; char *UNC; char *UNCip; - char *in6_addr; /* ipv6 address as human readable form of in6_addr */ + char *in6_addr; /* ipv6 address as human readable form of in6_addr */ char *iocharset; /* local code page for mapping to and from Unicode */ char source_rfc1001_name[16]; /* netbios name of client */ char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ @@ -82,13 +82,14 @@ struct smb_vol { bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ bool server_ino:1; /* use inode numbers from server ie UniqueId */ bool direct_io:1; - bool remap:1; /* set to remap seven reserved chars in filenames */ - bool posix_paths:1; /* unset to not ask for posix pathnames. */ + bool remap:1; /* set to remap seven reserved chars in filenames */ + bool posix_paths:1; /* unset to not ask for posix pathnames. */ bool no_linux_ext:1; bool sfu_emul:1; - bool nullauth:1; /* attempt to authenticate with null user */ - unsigned nocase; /* request case insensitive filenames */ - unsigned nobrl; /* disable sending byte range locks to srv */ + bool nullauth:1; /* attempt to authenticate with null user */ + bool nocase:1; /* request case insensitive filenames */ + bool nobrl:1; /* disable sending byte range locks to srv */ + bool seal:1; /* request transport encryption on share */ unsigned int rsize; unsigned int wsize; unsigned int sockopt; @@ -1273,8 +1274,12 @@ cifs_parse_mount_options(char *options, const char *devname, vol->no_psx_acl = 1; } else if (strnicmp(data, "sign", 4) == 0) { vol->secFlg |= CIFSSEC_MUST_SIGN; -/* } else if (strnicmp(data, "seal",4) == 0) { - vol->secFlg |= CIFSSEC_MUST_SEAL; */ + } else if (strnicmp(data, "seal", 4) == 0) { + /* we do not do the following in secFlags because seal + is a per tree connection (mount) not a per socket + or per-smb connection option in the protocol */ + /* vol->secFlg |= CIFSSEC_MUST_SEAL; */ + vol->seal = 1; } else if (strnicmp(data, "direct", 6) == 0) { vol->direct_io = 1; } else if (strnicmp(data, "forcedirectio", 13) == 0) { @@ -2126,6 +2131,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, for the retry flag is used */ tcon->retry = volume_info.retry; tcon->nocase = volume_info.nocase; + if (tcon->seal != volume_info.seal) + cERROR(1, ("transport encryption setting " + "conflicts with existing tid")); } else { tcon = tconInfoAlloc(); if (tcon == NULL) @@ -2159,6 +2167,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, atomic_inc(&pSesInfo->inUse); tcon->retry = volume_info.retry; tcon->nocase = volume_info.nocase; + tcon->seal = volume_info.seal; } } } -- cgit v1.2.3 From 519deca0496a4df07d15acf3181ca5d573bffdec Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 15 May 2008 14:43:20 -0400 Subject: ext4: Retry block allocation if new blocks are allocated from system zone. If the block allocator gets blocks out of system zone ext4 calls ext4_error. But if the file system is mounted with errors=continue retry block allocation. We need to mark the system zone blocks as in use to make sure retry don't pick them again System zone is the block range mapping block bitmap, inode bitmap and inode table. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/balloc.c | 17 +++++++++++------ fs/ext4/mballoc.c | 47 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index da994374ec3..30494c5da84 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -287,11 +287,11 @@ read_block_bitmap(struct super_block *sb, ext4_group_t block_group) (int)block_group, (unsigned long long)bitmap_blk); return NULL; } - if (!ext4_valid_block_bitmap(sb, desc, block_group, bh)) { - put_bh(bh); - return NULL; - } - + ext4_valid_block_bitmap(sb, desc, block_group, bh); + /* + * file system mounted not to panic on error, + * continue with corrupt bitmap + */ return bh; } /* @@ -1770,7 +1770,12 @@ allocated: "Allocating block in system zone - " "blocks from %llu, length %lu", ret_block, num); - goto out; + /* + * claim_block marked the blocks we allocated + * as in use. So we may want to selectively + * mark some of the blocks as free + */ + goto retry_alloc; } performed_allocation = 1; diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 1d7fde99452..873ad9b3418 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2736,7 +2736,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, struct ext4_sb_info *sbi; struct super_block *sb; ext4_fsblk_t block; - int err; + int err, len; BUG_ON(ac->ac_status != AC_STATUS_FOUND); BUG_ON(ac->ac_b_ex.fe_len <= 0); @@ -2770,14 +2770,27 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, + ac->ac_b_ex.fe_start + le32_to_cpu(es->s_first_data_block); - if (block == ext4_block_bitmap(sb, gdp) || - block == ext4_inode_bitmap(sb, gdp) || - in_range(block, ext4_inode_table(sb, gdp), - EXT4_SB(sb)->s_itb_per_group)) { - + len = ac->ac_b_ex.fe_len; + if (in_range(ext4_block_bitmap(sb, gdp), block, len) || + in_range(ext4_inode_bitmap(sb, gdp), block, len) || + in_range(block, ext4_inode_table(sb, gdp), + EXT4_SB(sb)->s_itb_per_group) || + in_range(block + len - 1, ext4_inode_table(sb, gdp), + EXT4_SB(sb)->s_itb_per_group)) { ext4_error(sb, __func__, "Allocating block in system zone - block = %llu", block); + /* File system mounted not to panic on error + * Fix the bitmap and repeat the block allocation + * We leak some of the blocks here. + */ + mb_set_bits(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group), + bitmap_bh->b_data, ac->ac_b_ex.fe_start, + ac->ac_b_ex.fe_len); + err = ext4_journal_dirty_metadata(handle, bitmap_bh); + if (!err) + err = -EAGAIN; + goto out_err; } #ifdef AGGRESSIVE_CHECK { @@ -4032,7 +4045,6 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, ac->ac_op = EXT4_MB_HISTORY_ALLOC; ext4_mb_normalize_request(ac, ar); - repeat: /* allocate space in core */ ext4_mb_regular_allocator(ac); @@ -4046,10 +4058,21 @@ repeat: } if (likely(ac->ac_status == AC_STATUS_FOUND)) { - ext4_mb_mark_diskspace_used(ac, handle); - *errp = 0; - block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex); - ar->len = ac->ac_b_ex.fe_len; + *errp = ext4_mb_mark_diskspace_used(ac, handle); + if (*errp == -EAGAIN) { + ac->ac_b_ex.fe_group = 0; + ac->ac_b_ex.fe_start = 0; + ac->ac_b_ex.fe_len = 0; + ac->ac_status = AC_STATUS_CONTINUE; + goto repeat; + } else if (*errp) { + ac->ac_b_ex.fe_len = 0; + ar->len = 0; + ext4_mb_show_ac(ac); + } else { + block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex); + ar->len = ac->ac_b_ex.fe_len; + } } else { freed = ext4_mb_discard_preallocations(sb, ac->ac_o_ex.fe_len); if (freed) @@ -4236,6 +4259,8 @@ do_more: ext4_error(sb, __func__, "Freeing blocks in system zone - " "Block = %lu, count = %lu", block, count); + /* err = 0. ext4_std_error should be a no op */ + goto error_return; } BUFFER_TRACE(bitmap_bh, "getting write access"); -- cgit v1.2.3 From 02c471cb17203c748e9bc87003052c1f46e5df69 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Thu, 15 May 2008 14:46:17 -0400 Subject: jbd2: update transaction t_state to T_COMMIT fix Updating the current transaction's t_state is protected by j_state_lock. We need to do the same when updating the t_state to T_COMMIT. Acked-by: Jan Kara Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" Signed-off-by: Andrew Morton --- fs/jbd2/commit.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index e0139786f71..4d99685fdce 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -560,7 +560,9 @@ void jbd2_journal_commit_transaction(journal_t *journal) * transaction! Now comes the tricky part: we need to write out * metadata. Loop over the transaction's entire buffer list: */ + spin_lock(&journal->j_state_lock); commit_transaction->t_state = T_COMMIT; + spin_unlock(&journal->j_state_lock); stats.u.run.rs_logging = jiffies; stats.u.run.rs_flushing = jbd2_time_diff(stats.u.run.rs_flushing, -- cgit v1.2.3 From de2db8d790b058fcd75d603780b913bd824972b3 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 16 May 2008 13:10:32 +0400 Subject: Fixed DFS code to work with new 'build_path_from_dentry', that returns full path if share in the dfs, now. Signed-off-by: Igor Mammedov Signed-off-by: Steve French --- fs/cifs/cifs_dfs_ref.c | 49 +------------------------------------------------ 1 file changed, 1 insertion(+), 48 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index f6fdecf6598..d82374c9e32 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -219,53 +219,6 @@ static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, } -static char *build_full_dfs_path_from_dentry(struct dentry *dentry) -{ - char *full_path = NULL; - char *search_path; - char *tmp_path; - size_t l_max_len; - struct cifs_sb_info *cifs_sb; - - if (dentry->d_inode == NULL) - return NULL; - - cifs_sb = CIFS_SB(dentry->d_inode->i_sb); - - if (cifs_sb->tcon == NULL) - return NULL; - - search_path = build_path_from_dentry(dentry); - if (search_path == NULL) - return NULL; - - if (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS) { - int i; - /* we should use full path name for correct working with DFS */ - l_max_len = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE+1) + - strnlen(search_path, MAX_PATHCONF) + 1; - tmp_path = kmalloc(l_max_len, GFP_KERNEL); - if (tmp_path == NULL) { - kfree(search_path); - return NULL; - } - strncpy(tmp_path, cifs_sb->tcon->treeName, l_max_len); - tmp_path[l_max_len-1] = 0; - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) - for (i = 0; i < l_max_len; i++) { - if (tmp_path[i] == '\\') - tmp_path[i] = '/'; - } - strncat(tmp_path, search_path, l_max_len - strlen(tmp_path)); - - full_path = tmp_path; - kfree(search_path); - } else { - full_path = search_path; - } - return full_path; -} - static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, struct list_head *mntlist) { @@ -333,7 +286,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) goto out_err; } - full_path = build_full_dfs_path_from_dentry(dentry); + full_path = build_path_from_dentry(dentry); if (full_path == NULL) { rc = -ENOMEM; goto out_err; -- cgit v1.2.3 From b0b539739fe9b7d75002412a787cfdf4efddbc33 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 5 May 2008 11:45:41 -0400 Subject: NFS: Ensure that 'noac' and/or 'actimeo=0' turn off attribute caching Both the 'noac' and 'actimeo=0' mount options should ensure that attributes are not cached, however a bug in nfs_attribute_timeout() means that currently, the attributes may in fact get cached for up to one jiffy. This has been seen to cause corruption in some applications. The reason for the bug is that the time_in_range() test returns 'true' as long as the current time lies between nfsi->read_cache_jiffies and nfsi->read_cache_jiffies + nfsi->attrtimeo. In other words, if jiffies equals nfsi->read_cache_jiffies, then we still cache the attribute data. Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'fs') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 5cb3345eb69..2501b864f7c 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -707,6 +707,13 @@ int nfs_attribute_timeout(struct inode *inode) if (nfs_have_delegation(inode, FMODE_READ)) return 0; + /* + * Special case: if the attribute timeout is set to 0, then always + * treat the cache as having expired (unless holding + * a delegation). + */ + if (nfsi->attrtimeo == 0) + return 1; return !time_in_range(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); } -- cgit v1.2.3 From 38def50fabc479dc96ea6bd2cb2526e0dfc36fa4 Mon Sep 17 00:00:00 2001 From: Fred Isaman Date: Thu, 1 May 2008 20:03:22 +0300 Subject: nfs: fix race in nfs_dirty_request When called from nfs_flush_incompatible, the req is not locked, so req->wb_page might be set to NULL before it is used by PageWriteback. Signed-off-by: Fred Isaman Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust --- fs/nfs/write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 1ade11d1ba0..6d8ace3e325 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -415,7 +415,7 @@ nfs_dirty_request(struct nfs_page *req) if (page == NULL || test_bit(PG_NEED_COMMIT, &req->wb_flags)) return 0; - return !PageWriteback(req->wb_page); + return !PageWriteback(page); } #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) -- cgit v1.2.3 From 3a6258e1fb5ff717dcefa04afc35f81aaae3f3e0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 6 May 2008 13:32:40 -0400 Subject: NFSv4: Check the return value of decode_compound_hdr_arg() If decode_compound_hdr_arg() returns a resource error, then we cannot proceed to process the callback. Return a 'GARBAGE_ARGS' rpc-level error to the caller instead. If, however, the minor version field is incorrect, then we need to propagate the resulting NFS4ERR_MINOR_VERS_MISMATCH error back as the compound status field (setting the nops field to 0). Finally, if encode_compound_hdr_res() returns an error, we need to return an RPC_SYSTEM_ERR to the caller. Signed-off-by: Trond Myklebust --- fs/nfs/callback_xdr.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 13619d24f02..646d4d85072 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -401,12 +401,12 @@ static __be32 process_op(struct svc_rqst *rqstp, */ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp) { - struct cb_compound_hdr_arg hdr_arg; - struct cb_compound_hdr_res hdr_res; + struct cb_compound_hdr_arg hdr_arg = { 0 }; + struct cb_compound_hdr_res hdr_res = { NULL }; struct xdr_stream xdr_in, xdr_out; __be32 *p; __be32 status; - unsigned int nops = 1; + unsigned int nops = 0; dprintk("%s: start\n", __FUNCTION__); @@ -415,20 +415,20 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); xdr_init_encode(&xdr_out, &rqstp->rq_res, p); - decode_compound_hdr_arg(&xdr_in, &hdr_arg); + status = decode_compound_hdr_arg(&xdr_in, &hdr_arg); + if (status == __constant_htonl(NFS4ERR_RESOURCE)) + return rpc_garbage_args; + hdr_res.taglen = hdr_arg.taglen; hdr_res.tag = hdr_arg.tag; - hdr_res.nops = NULL; - encode_compound_hdr_res(&xdr_out, &hdr_res); + if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) + return rpc_system_err; - for (;;) { + while (status == 0 && nops != hdr_arg.nops) { status = process_op(rqstp, &xdr_in, argp, &xdr_out, resp); - if (status != 0) - break; - if (nops == hdr_arg.nops) - break; nops++; } + *hdr_res.status = status; *hdr_res.nops = htonl(nops); dprintk("%s: done, status = %u\n", __FUNCTION__, ntohl(status)); -- cgit v1.2.3 From 46c8ac74250a396aca855e494f49a960797a6b5e Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 2 May 2008 13:42:42 -0700 Subject: nfs/lsm: make NFSv4 set LSM mount options NFSv3 get_sb operations call into the LSM layer to set security options passed from userspace. NFSv4 hooks were not originally added since it was reasonably late in the merge window and NFSv3 was the only thing that had regressed (v4 has never supported any LSM options) This patch makes NFSv4 call into the LSM to set security options rather than just blindly dropping them with no notice to the user as happens today. This patch was tested in a simple NFSv4 environment with the context= option and appeared to work as expected. Signed-off-by: Eric Paris Cc: Trond Myklebust Cc: "J. Bruce Fields" Cc: Stephen Smalley Acked-by: James Morris Cc: Casey Schaufler Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'fs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 7226a506f3c..5ed86ac0fd9 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2015,6 +2015,10 @@ static int nfs4_get_sb(struct file_system_type *fs_type, goto error_splat_super; } + error = security_sb_set_mnt_opts(s, &data.lsm_opts); + if (error) + goto error_splat_root; + s->s_flags |= MS_ACTIVE; mnt->mnt_sb = s; mnt->mnt_root = mntroot; @@ -2031,6 +2035,8 @@ out_free: nfs_free_server(server); goto out; +error_splat_root: + dput(mntroot); error_splat_super: up_write(&s->s_umount); deactivate_super(s); @@ -2114,6 +2120,8 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, mnt->mnt_sb = s; mnt->mnt_root = mntroot; + security_sb_clone_mnt_opts(data->sb, s); + dprintk("<-- nfs4_xdev_get_sb() = 0\n"); return 0; @@ -2197,6 +2205,8 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, mnt->mnt_sb = s; mnt->mnt_root = mntroot; + security_sb_clone_mnt_opts(data->sb, s); + dprintk("<-- nfs4_referral_get_sb() = 0\n"); return 0; -- cgit v1.2.3 From 3110ff8048fb757b36112b044b384aea9c44d6e4 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Fri, 2 May 2008 13:42:44 -0700 Subject: nfs: replace remaining __FUNCTION__ occurrences __FUNCTION__ is gcc-specific, use __func__ Signed-off-by: Harvey Harrison Cc: Trond Myklebust Cc: "J. Bruce Fields" Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust --- fs/nfs/callback.c | 2 +- fs/nfs/callback_proc.c | 4 +- fs/nfs/callback_xdr.c | 18 ++++----- fs/nfs/client.c | 8 ++-- fs/nfs/delegation.c | 4 +- fs/nfs/dir.c | 18 ++++----- fs/nfs/file.c | 2 +- fs/nfs/inode.c | 4 +- fs/nfs/namespace.c | 8 ++-- fs/nfs/nfs3proc.c | 6 +-- fs/nfs/nfs4namespace.c | 12 +++--- fs/nfs/nfs4proc.c | 32 ++++++++-------- fs/nfs/nfs4renewd.c | 10 ++--- fs/nfs/nfs4state.c | 6 +-- fs/nfs/nfs4xdr.c | 100 ++++++++++++++++++++++++------------------------- fs/nfs/proc.c | 8 ++-- fs/nfs/read.c | 2 +- fs/nfs/super.c | 2 +- 18 files changed, 123 insertions(+), 123 deletions(-) (limited to 'fs') diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 5606ae3d72d..c1e7c830062 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -182,7 +182,7 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp) if (clp == NULL) return SVC_DROP; - dprintk("%s: %s NFSv4 callback!\n", __FUNCTION__, + dprintk("%s: %s NFSv4 callback!\n", __func__, svc_print_addr(rqstp, buf, sizeof(buf))); nfs_put_client(clp); diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 15f7785048d..f7e83e23cf9 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -57,7 +57,7 @@ out_iput: out_putclient: nfs_put_client(clp); out: - dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status)); + dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status)); return res->status; } @@ -98,6 +98,6 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) nfs_put_client(prev); } while (clp != NULL); out: - dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); + dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); return res; } diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 646d4d85072..dd0ef34b584 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -141,7 +141,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound /* We do not like overly long tags! */ if (hdr->taglen > CB_OP_TAGLEN_MAXSZ - 12) { printk("NFSv4 CALLBACK %s: client sent tag of length %u\n", - __FUNCTION__, hdr->taglen); + __func__, hdr->taglen); return htonl(NFS4ERR_RESOURCE); } p = read_buf(xdr, 12); @@ -151,7 +151,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound /* Check minor version is zero. */ if (minor_version != 0) { printk(KERN_WARNING "%s: NFSv4 server callback with illegal minor version %u!\n", - __FUNCTION__, minor_version); + __func__, minor_version); return htonl(NFS4ERR_MINOR_VERS_MISMATCH); } hdr->callback_ident = ntohl(*p++); @@ -179,7 +179,7 @@ static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr args->addr = svc_addr(rqstp); status = decode_bitmap(xdr, args->bitmap); out: - dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status)); + dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; } @@ -200,7 +200,7 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, args->truncate = ntohl(*p); status = decode_fh(xdr, &args->fh); out: - dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status)); + dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; } @@ -349,7 +349,7 @@ static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, status = encode_attr_mtime(xdr, res->bitmap, &res->mtime); *savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1))); out: - dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status)); + dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; } @@ -363,7 +363,7 @@ static __be32 process_op(struct svc_rqst *rqstp, long maxlen; __be32 res; - dprintk("%s: start\n", __FUNCTION__); + dprintk("%s: start\n", __func__); status = decode_op_hdr(xdr_in, &op_nr); if (likely(status == 0)) { switch (op_nr) { @@ -392,7 +392,7 @@ static __be32 process_op(struct svc_rqst *rqstp, status = res; if (op->encode_res != NULL && status == 0) status = op->encode_res(rqstp, xdr_out, resp); - dprintk("%s: done, status = %d\n", __FUNCTION__, ntohl(status)); + dprintk("%s: done, status = %d\n", __func__, ntohl(status)); return status; } @@ -408,7 +408,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r __be32 status; unsigned int nops = 0; - dprintk("%s: start\n", __FUNCTION__); + dprintk("%s: start\n", __func__); xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); @@ -431,7 +431,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r *hdr_res.status = status; *hdr_res.nops = htonl(nops); - dprintk("%s: done, status = %u\n", __FUNCTION__, ntohl(status)); + dprintk("%s: done, status = %u\n", __func__, ntohl(status)); return rpc_success; } diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 89ac5bb0401..f2a092ca69b 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -488,7 +488,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp, clnt = rpc_create(&args); if (IS_ERR(clnt)) { dprintk("%s: cannot create RPC client. Error = %ld\n", - __FUNCTION__, PTR_ERR(clnt)); + __func__, PTR_ERR(clnt)); return PTR_ERR(clnt); } @@ -576,7 +576,7 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, server->client = rpc_clone_client(clp->cl_rpcclient); if (IS_ERR(server->client)) { - dprintk("%s: couldn't create rpc_client!\n", __FUNCTION__); + dprintk("%s: couldn't create rpc_client!\n", __func__); return PTR_ERR(server->client); } @@ -590,7 +590,7 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, auth = rpcauth_create(pseudoflavour, server->client); if (IS_ERR(auth)) { - dprintk("%s: couldn't create credcache!\n", __FUNCTION__); + dprintk("%s: couldn't create credcache!\n", __func__); return PTR_ERR(auth); } } @@ -985,7 +985,7 @@ static int nfs4_init_client(struct nfs_client *clp, error = nfs_idmap_new(clp); if (error < 0) { dprintk("%s: failed to create idmapper. Error = %d\n", - __FUNCTION__, error); + __func__, error); goto error; } __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 00a5e4405e1..cc563cfa694 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -60,7 +60,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ switch (status) { default: printk(KERN_ERR "%s: unhandled error %d.\n", - __FUNCTION__, status); + __func__, status); case -NFS4ERR_EXPIRED: /* kill_proc(fl->fl_pid, SIGLOST, 1); */ case -NFS4ERR_STALE_CLIENTID: @@ -186,7 +186,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct */ dfprintk(FILE, "%s: server %s handed out " "a duplicate delegation!\n", - __FUNCTION__, clp->cl_hostname); + __func__, clp->cl_hostname); if (delegation->type <= nfsi->delegation->type) { freeme = delegation; delegation = NULL; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f288b3ecab4..58d43daec08 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -180,7 +180,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) int error; dfprintk(DIRCACHE, "NFS: %s: reading cookie %Lu into page %lu\n", - __FUNCTION__, (long long)desc->entry->cookie, + __func__, (long long)desc->entry->cookie, page->index); again: @@ -256,7 +256,7 @@ int find_dirent(nfs_readdir_descriptor_t *desc) while((status = dir_decode(desc)) == 0) { dfprintk(DIRCACHE, "NFS: %s: examining cookie %Lu\n", - __FUNCTION__, (unsigned long long)entry->cookie); + __func__, (unsigned long long)entry->cookie); if (entry->prev_cookie == *desc->dir_cookie) break; if (loop_count++ > 200) { @@ -315,7 +315,7 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) int status; dfprintk(DIRCACHE, "NFS: %s: searching page %ld for target %Lu\n", - __FUNCTION__, desc->page_index, + __func__, desc->page_index, (long long) *desc->dir_cookie); /* If we find the page in the page_cache, we cannot be sure @@ -339,7 +339,7 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) if (status < 0) dir_page_release(desc); out: - dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __FUNCTION__, status); + dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, status); return status; } @@ -380,7 +380,7 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) } } - dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __FUNCTION__, res); + dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, res); return res; } @@ -506,7 +506,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, desc->entry->eof = 0; out: dfprintk(DIRCACHE, "NFS: %s: returns %d\n", - __FUNCTION__, status); + __func__, status); return status; out_release: dir_page_release(desc); @@ -780,7 +780,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) if (is_bad_inode(inode)) { dfprintk(LOOKUPCACHE, "%s: %s/%s has dud inode\n", - __FUNCTION__, dentry->d_parent->d_name.name, + __func__, dentry->d_parent->d_name.name, dentry->d_name.name); goto out_bad; } @@ -808,7 +808,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) unlock_kernel(); dput(parent); dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n", - __FUNCTION__, dentry->d_parent->d_name.name, + __func__, dentry->d_parent->d_name.name, dentry->d_name.name); return 1; out_zap_parent: @@ -827,7 +827,7 @@ out_zap_parent: unlock_kernel(); dput(parent); dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", - __FUNCTION__, dentry->d_parent->d_name.name, + __func__, dentry->d_parent->d_name.name, dentry->d_name.name); return 0; } diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 3536b01164f..d84a3d8f32a 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -526,7 +526,7 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) if (res < 0) dprintk(KERN_WARNING "%s: VFS is out of sync with lock manager" " - error %d!\n", - __FUNCTION__, res); + __func__, res); return res; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 2501b864f7c..421d338c698 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1002,7 +1002,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) unsigned long now = jiffies; dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", - __FUNCTION__, inode->i_sb->s_id, inode->i_ino, + __func__, inode->i_sb->s_id, inode->i_ino, atomic_read(&inode->i_count), fattr->valid); if (nfsi->fileid != fattr->fileid) @@ -1126,7 +1126,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) * Big trouble! The inode has become a different object. */ printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n", - __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode); + __func__, inode->i_ino, inode->i_mode, fattr->mode); out_err: /* * No need to worry about unhashing the dentry, as the diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index af4d0f1e402..fca518006a5 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -106,7 +106,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) dprintk("--> nfs_follow_mountpoint()\n"); BUG_ON(IS_ROOT(dentry)); - dprintk("%s: enter\n", __FUNCTION__); + dprintk("%s: enter\n", __func__); dput(nd->path.dentry); nd->path.dentry = dget(dentry); @@ -143,7 +143,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) nd->path.dentry = dget(mnt->mnt_root); schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); out: - dprintk("%s: done, returned %d\n", __FUNCTION__, err); + dprintk("%s: done, returned %d\n", __func__, err); dprintk("<-- nfs_follow_mountpoint() = %d\n", err); return ERR_PTR(err); @@ -230,7 +230,7 @@ static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, dprintk("--> nfs_do_submount()\n"); - dprintk("%s: submounting on %s/%s\n", __FUNCTION__, + dprintk("%s: submounting on %s/%s\n", __func__, dentry->d_parent->d_name.name, dentry->d_name.name); if (page == NULL) @@ -243,7 +243,7 @@ static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, free_page: free_page((unsigned long)page); out: - dprintk("%s: done\n", __FUNCTION__); + dprintk("%s: done\n", __func__); dprintk("<-- nfs_do_submount() = %p\n", mnt); return mnt; diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 549dbce714a..c3523ad03ed 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -63,15 +63,15 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, }; int status; - dprintk("%s: call fsinfo\n", __FUNCTION__); + dprintk("%s: call fsinfo\n", __func__); nfs_fattr_init(info->fattr); status = rpc_call_sync(client, &msg, 0); - dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status); + dprintk("%s: reply fsinfo: %d\n", __func__, status); if (!(info->fattr->valid & NFS_ATTR_FATTR)) { msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; msg.rpc_resp = info->fattr; status = rpc_call_sync(client, &msg, 0); - dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); + dprintk("%s: reply getattr: %d\n", __func__, status); } return status; } diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 5f9ba41ed5b..b112857301f 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -86,7 +86,7 @@ static int nfs4_validate_fspath(const struct vfsmount *mnt_parent, if (strncmp(path, fs_path, strlen(fs_path)) != 0) { dprintk("%s: path %s does not begin with fsroot %s\n", - __FUNCTION__, path, fs_path); + __func__, path, fs_path); return -ENOENT; } @@ -134,7 +134,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, if (locations == NULL || locations->nlocations <= 0) goto out; - dprintk("%s: referral at %s/%s\n", __FUNCTION__, + dprintk("%s: referral at %s/%s\n", __func__, dentry->d_parent->d_name.name, dentry->d_name.name); page = (char *) __get_free_page(GFP_USER); @@ -204,7 +204,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, out: free_page((unsigned long) page); free_page((unsigned long) page2); - dprintk("%s: done\n", __FUNCTION__); + dprintk("%s: done\n", __func__); return mnt; } @@ -223,7 +223,7 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr int err; /* BUG_ON(IS_ROOT(dentry)); */ - dprintk("%s: enter\n", __FUNCTION__); + dprintk("%s: enter\n", __func__); page = alloc_page(GFP_KERNEL); if (page == NULL) @@ -238,7 +238,7 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr parent = dget_parent(dentry); dprintk("%s: getting locations for %s/%s\n", - __FUNCTION__, parent->d_name.name, dentry->d_name.name); + __func__, parent->d_name.name, dentry->d_name.name); err = nfs4_proc_fs_locations(parent->d_inode, &dentry->d_name, fs_locations, page); dput(parent); @@ -252,6 +252,6 @@ out_free: __free_page(page); kfree(fs_locations); out: - dprintk("%s: done\n", __FUNCTION__); + dprintk("%s: done\n", __func__); return mnt; } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index dbc09271af0..f533318b005 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -73,7 +73,7 @@ int nfs4_map_errors(int err) { if (err < -1000) { dprintk("%s could not handle NFSv4 error %d\n", - __FUNCTION__, -err); + __func__, -err); return -EIO; } return err; @@ -1578,7 +1578,7 @@ static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct goto out; /* Make sure server returned a different fsid for the referral */ if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) { - dprintk("%s: server did not return a different fsid for a referral at %s\n", __FUNCTION__, name->name); + dprintk("%s: server did not return a different fsid for a referral at %s\n", __func__, name->name); status = -EIO; goto out; } @@ -2211,7 +2211,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, }; int status; - dprintk("%s: dentry = %s/%s, cookie = %Lu\n", __FUNCTION__, + dprintk("%s: dentry = %s/%s, cookie = %Lu\n", __func__, dentry->d_parent->d_name.name, dentry->d_name.name, (unsigned long long)cookie); @@ -2223,7 +2223,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, nfs_invalidate_atime(dir); - dprintk("%s: returns %d\n", __FUNCTION__, status); + dprintk("%s: returns %d\n", __func__, status); return status; } @@ -3342,7 +3342,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) struct nfs4_lockdata *data = calldata; struct nfs4_state *state = data->lsp->ls_state; - dprintk("%s: begin!\n", __FUNCTION__); + dprintk("%s: begin!\n", __func__); if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) return; /* Do we need to do an open_to_lock_owner? */ @@ -3356,14 +3356,14 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) data->arg.new_lock_owner = 0; data->timestamp = jiffies; rpc_call_start(task); - dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status); + dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); } static void nfs4_lock_done(struct rpc_task *task, void *calldata) { struct nfs4_lockdata *data = calldata; - dprintk("%s: begin!\n", __FUNCTION__); + dprintk("%s: begin!\n", __func__); data->rpc_status = task->tk_status; if (RPC_ASSASSINATED(task)) @@ -3381,14 +3381,14 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); } out: - dprintk("%s: done, ret = %d!\n", __FUNCTION__, data->rpc_status); + dprintk("%s: done, ret = %d!\n", __func__, data->rpc_status); } static void nfs4_lock_release(void *calldata) { struct nfs4_lockdata *data = calldata; - dprintk("%s: begin!\n", __FUNCTION__); + dprintk("%s: begin!\n", __func__); nfs_free_seqid(data->arg.open_seqid); if (data->cancelled != 0) { struct rpc_task *task; @@ -3396,13 +3396,13 @@ static void nfs4_lock_release(void *calldata) data->arg.lock_seqid); if (!IS_ERR(task)) rpc_put_task(task); - dprintk("%s: cancelling lock!\n", __FUNCTION__); + dprintk("%s: cancelling lock!\n", __func__); } else nfs_free_seqid(data->arg.lock_seqid); nfs4_put_lock_state(data->lsp); put_nfs_open_context(data->ctx); kfree(data); - dprintk("%s: done!\n", __FUNCTION__); + dprintk("%s: done!\n", __func__); } static const struct rpc_call_ops nfs4_lock_ops = { @@ -3428,7 +3428,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f }; int ret; - dprintk("%s: begin!\n", __FUNCTION__); + dprintk("%s: begin!\n", __func__); data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file), fl->fl_u.nfs4_fl.owner); if (data == NULL) @@ -3451,7 +3451,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f } else data->cancelled = 1; rpc_put_task(task); - dprintk("%s: done, ret = %d!\n", __FUNCTION__, ret); + dprintk("%s: done, ret = %d!\n", __func__, ret); return ret; } @@ -3527,7 +3527,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock /* Note: we always want to sleep here! */ request->fl_flags = fl_flags | FL_SLEEP; if (do_vfs_lock(request->fl_file, request) < 0) - printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); + printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__); out_unlock: up_read(&clp->cl_sem); out: @@ -3665,12 +3665,12 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, }; int status; - dprintk("%s: start\n", __FUNCTION__); + dprintk("%s: start\n", __func__); nfs_fattr_init(&fs_locations->fattr); fs_locations->server = server; fs_locations->nlocations = 0; status = rpc_call_sync(server->client, &msg, 0); - dprintk("%s: returned status = %d\n", __FUNCTION__, status); + dprintk("%s: returned status = %d\n", __func__, status); return status; } diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 5e2e4af1a0e..3305acbbe2a 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c @@ -66,7 +66,7 @@ nfs4_renew_state(struct work_struct *work) unsigned long last, now; down_read(&clp->cl_sem); - dprintk("%s: start\n", __FUNCTION__); + dprintk("%s: start\n", __func__); /* Are there any active superblocks? */ if (list_empty(&clp->cl_superblocks)) goto out; @@ -92,17 +92,17 @@ nfs4_renew_state(struct work_struct *work) spin_lock(&clp->cl_lock); } else dprintk("%s: failed to call renewd. Reason: lease not expired \n", - __FUNCTION__); + __func__); if (timeout < 5 * HZ) /* safeguard */ timeout = 5 * HZ; dprintk("%s: requeueing work. Lease period = %ld\n", - __FUNCTION__, (timeout + HZ - 1) / HZ); + __func__, (timeout + HZ - 1) / HZ); cancel_delayed_work(&clp->cl_renewd); schedule_delayed_work(&clp->cl_renewd, timeout); spin_unlock(&clp->cl_lock); out: up_read(&clp->cl_sem); - dprintk("%s: done\n", __FUNCTION__); + dprintk("%s: done\n", __func__); } /* Must be called with clp->cl_sem locked for writes */ @@ -117,7 +117,7 @@ nfs4_schedule_state_renewal(struct nfs_client *clp) if (timeout < 5 * HZ) timeout = 5 * HZ; dprintk("%s: requeueing work. Lease period = %ld\n", - __FUNCTION__, (timeout + HZ - 1) / HZ); + __func__, (timeout + HZ - 1) / HZ); cancel_delayed_work(&clp->cl_renewd); schedule_delayed_work(&clp->cl_renewd, timeout); set_bit(NFS_CS_RENEWD, &clp->cl_res_state); diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 46eb624e4f1..5a1e02c8b75 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -828,7 +828,7 @@ static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_s switch (status) { default: printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", - __FUNCTION__, status); + __func__, status); case -NFS4ERR_EXPIRED: case -NFS4ERR_NO_GRACE: case -NFS4ERR_RECLAIM_BAD: @@ -869,14 +869,14 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n list_for_each_entry(lock, &state->lock_states, ls_locks) { if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) printk("%s: Lock reclaim failed!\n", - __FUNCTION__); + __func__); } continue; } switch (status) { default: printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", - __FUNCTION__, status); + __func__, status); case -ENOENT: case -NFS4ERR_RECLAIM_BAD: case -NFS4ERR_RECLAIM_CONFLICT: diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5a2d64927b3..b916297d233 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1831,7 +1831,7 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->count); dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", - __FUNCTION__, replen, args->pages, + __func__, replen, args->pages, args->pgbase, args->count); out: @@ -2192,9 +2192,9 @@ out: p = xdr_inline_decode(xdr, nbytes); \ if (unlikely(!p)) { \ dprintk("nfs: %s: prematurely hit end of receive" \ - " buffer\n", __FUNCTION__); \ + " buffer\n", __func__); \ dprintk("nfs: %s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \ - __FUNCTION__, xdr->p, nbytes, xdr->end); \ + __func__, xdr->p, nbytes, xdr->end); \ return -EIO; \ } \ } while (0) @@ -2306,12 +2306,12 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t * READ_BUF(4); READ32(*type); if (*type < NF4REG || *type > NF4NAMEDATTR) { - dprintk("%s: bad type %d\n", __FUNCTION__, *type); + dprintk("%s: bad type %d\n", __func__, *type); return -EIO; } bitmap[0] &= ~FATTR4_WORD0_TYPE; } - dprintk("%s: type=0%o\n", __FUNCTION__, nfs_type2fmt[*type].nfs2type); + dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type].nfs2type); return 0; } @@ -2327,7 +2327,7 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t READ64(*change); bitmap[0] &= ~FATTR4_WORD0_CHANGE; } - dprintk("%s: change attribute=%Lu\n", __FUNCTION__, + dprintk("%s: change attribute=%Lu\n", __func__, (unsigned long long)*change); return 0; } @@ -2344,7 +2344,7 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t * READ64(*size); bitmap[0] &= ~FATTR4_WORD0_SIZE; } - dprintk("%s: file size=%Lu\n", __FUNCTION__, (unsigned long long)*size); + dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size); return 0; } @@ -2360,7 +2360,7 @@ static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, ui READ32(*res); bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT; } - dprintk("%s: link support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true"); + dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true"); return 0; } @@ -2376,7 +2376,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, READ32(*res); bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT; } - dprintk("%s: symlink support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true"); + dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true"); return 0; } @@ -2394,7 +2394,7 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs READ64(fsid->minor); bitmap[0] &= ~FATTR4_WORD0_FSID; } - dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __FUNCTION__, + dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__, (unsigned long long)fsid->major, (unsigned long long)fsid->minor); return 0; @@ -2412,7 +2412,7 @@ static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint READ32(*res); bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME; } - dprintk("%s: file size=%u\n", __FUNCTION__, (unsigned int)*res); + dprintk("%s: file size=%u\n", __func__, (unsigned int)*res); return 0; } @@ -2428,7 +2428,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint READ32(*res); bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT; } - dprintk("%s: ACLs supported=%u\n", __FUNCTION__, (unsigned int)*res); + dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res); return 0; } @@ -2444,7 +2444,7 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t READ64(*fileid); bitmap[0] &= ~FATTR4_WORD0_FILEID; } - dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid); + dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); return 0; } @@ -2460,7 +2460,7 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma READ64(*fileid); bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; } - dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid); + dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); return 0; } @@ -2477,7 +2477,7 @@ static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin READ64(*res); bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL; } - dprintk("%s: files avail=%Lu\n", __FUNCTION__, (unsigned long long)*res); + dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res); return status; } @@ -2494,7 +2494,7 @@ static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint READ64(*res); bitmap[0] &= ~FATTR4_WORD0_FILES_FREE; } - dprintk("%s: files free=%Lu\n", __FUNCTION__, (unsigned long long)*res); + dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res); return status; } @@ -2511,7 +2511,7 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin READ64(*res); bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL; } - dprintk("%s: files total=%Lu\n", __FUNCTION__, (unsigned long long)*res); + dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res); return status; } @@ -2569,7 +2569,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st status = 0; if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS))) goto out; - dprintk("%s: fsroot ", __FUNCTION__); + dprintk("%s: fsroot ", __func__); status = decode_pathname(xdr, &res->fs_path); if (unlikely(status != 0)) goto out; @@ -2586,7 +2586,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st READ32(m); loc->nservers = 0; - dprintk("%s: servers ", __FUNCTION__); + dprintk("%s: servers ", __func__); while (loc->nservers < m) { struct nfs4_string *server = &loc->servers[loc->nservers]; status = decode_opaque_inline(xdr, &server->len, &server->data); @@ -2599,7 +2599,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st unsigned int i; dprintk("%s: using first %u of %u servers " "returned for location %u\n", - __FUNCTION__, + __func__, NFS4_FS_LOCATION_MAXSERVERS, m, res->nlocations); for (i = loc->nservers; i < m; i++) { @@ -2618,7 +2618,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st res->nlocations++; } out: - dprintk("%s: fs_locations done, error = %d\n", __FUNCTION__, status); + dprintk("%s: fs_locations done, error = %d\n", __func__, status); return status; out_eio: status = -EIO; @@ -2638,7 +2638,7 @@ static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uin READ64(*res); bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE; } - dprintk("%s: maxfilesize=%Lu\n", __FUNCTION__, (unsigned long long)*res); + dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res); return status; } @@ -2655,7 +2655,7 @@ static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ READ32(*maxlink); bitmap[0] &= ~FATTR4_WORD0_MAXLINK; } - dprintk("%s: maxlink=%u\n", __FUNCTION__, *maxlink); + dprintk("%s: maxlink=%u\n", __func__, *maxlink); return status; } @@ -2672,7 +2672,7 @@ static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ READ32(*maxname); bitmap[0] &= ~FATTR4_WORD0_MAXNAME; } - dprintk("%s: maxname=%u\n", __FUNCTION__, *maxname); + dprintk("%s: maxname=%u\n", __func__, *maxname); return status; } @@ -2693,7 +2693,7 @@ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ *res = (uint32_t)maxread; bitmap[0] &= ~FATTR4_WORD0_MAXREAD; } - dprintk("%s: maxread=%lu\n", __FUNCTION__, (unsigned long)*res); + dprintk("%s: maxread=%lu\n", __func__, (unsigned long)*res); return status; } @@ -2714,7 +2714,7 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32 *res = (uint32_t)maxwrite; bitmap[0] &= ~FATTR4_WORD0_MAXWRITE; } - dprintk("%s: maxwrite=%lu\n", __FUNCTION__, (unsigned long)*res); + dprintk("%s: maxwrite=%lu\n", __func__, (unsigned long)*res); return status; } @@ -2731,7 +2731,7 @@ static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t * *mode &= ~S_IFMT; bitmap[1] &= ~FATTR4_WORD1_MODE; } - dprintk("%s: file mode=0%o\n", __FUNCTION__, (unsigned int)*mode); + dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode); return 0; } @@ -2747,7 +2747,7 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t READ32(*nlink); bitmap[1] &= ~FATTR4_WORD1_NUMLINKS; } - dprintk("%s: nlink=%u\n", __FUNCTION__, (unsigned int)*nlink); + dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink); return 0; } @@ -2766,13 +2766,13 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf if (len < XDR_MAX_NETOBJ) { if (nfs_map_name_to_uid(clp, (char *)p, len, uid) != 0) dprintk("%s: nfs_map_name_to_uid failed!\n", - __FUNCTION__); + __func__); } else dprintk("%s: name too long (%u)!\n", - __FUNCTION__, len); + __func__, len); bitmap[1] &= ~FATTR4_WORD1_OWNER; } - dprintk("%s: uid=%d\n", __FUNCTION__, (int)*uid); + dprintk("%s: uid=%d\n", __func__, (int)*uid); return 0; } @@ -2791,13 +2791,13 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf if (len < XDR_MAX_NETOBJ) { if (nfs_map_group_to_gid(clp, (char *)p, len, gid) != 0) dprintk("%s: nfs_map_group_to_gid failed!\n", - __FUNCTION__); + __func__); } else dprintk("%s: name too long (%u)!\n", - __FUNCTION__, len); + __func__, len); bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP; } - dprintk("%s: gid=%d\n", __FUNCTION__, (int)*gid); + dprintk("%s: gid=%d\n", __func__, (int)*gid); return 0; } @@ -2820,7 +2820,7 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde *rdev = tmp; bitmap[1] &= ~ FATTR4_WORD1_RAWDEV; } - dprintk("%s: rdev=(0x%x:0x%x)\n", __FUNCTION__, major, minor); + dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor); return 0; } @@ -2837,7 +2837,7 @@ static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin READ64(*res); bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL; } - dprintk("%s: space avail=%Lu\n", __FUNCTION__, (unsigned long long)*res); + dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res); return status; } @@ -2854,7 +2854,7 @@ static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint READ64(*res); bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE; } - dprintk("%s: space free=%Lu\n", __FUNCTION__, (unsigned long long)*res); + dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res); return status; } @@ -2871,7 +2871,7 @@ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uin READ64(*res); bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL; } - dprintk("%s: space total=%Lu\n", __FUNCTION__, (unsigned long long)*res); + dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res); return status; } @@ -2887,7 +2887,7 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint READ64(*used); bitmap[1] &= ~FATTR4_WORD1_SPACE_USED; } - dprintk("%s: space used=%Lu\n", __FUNCTION__, + dprintk("%s: space used=%Lu\n", __func__, (unsigned long long)*used); return 0; } @@ -2918,7 +2918,7 @@ static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, str status = decode_attr_time(xdr, time); bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS; } - dprintk("%s: atime=%ld\n", __FUNCTION__, (long)time->tv_sec); + dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec); return status; } @@ -2934,7 +2934,7 @@ static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, s status = decode_attr_time(xdr, time); bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA; } - dprintk("%s: ctime=%ld\n", __FUNCTION__, (long)time->tv_sec); + dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec); return status; } @@ -2950,7 +2950,7 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str status = decode_attr_time(xdr, time); bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY; } - dprintk("%s: mtime=%ld\n", __FUNCTION__, (long)time->tv_sec); + dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec); return status; } @@ -2962,7 +2962,7 @@ static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrl if (unlikely(attrwords != nwords)) { dprintk("%s: server returned incorrect attribute length: " "%u %c %u\n", - __FUNCTION__, + __func__, attrwords << 2, (attrwords < nwords) ? '<' : '>', nwords << 2); @@ -3067,7 +3067,7 @@ static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_re goto xdr_error; status = verify_attr_len(xdr, savep, attrlen); xdr_error: - dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status); + dprintk("%s: xdr returned %d!\n", __func__, -status); return status; } @@ -3100,7 +3100,7 @@ static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) status = verify_attr_len(xdr, savep, attrlen); xdr_error: - dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status); + dprintk("%s: xdr returned %d!\n", __func__, -status); return status; } @@ -3125,7 +3125,7 @@ static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf status = verify_attr_len(xdr, savep, attrlen); xdr_error: - dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status); + dprintk("%s: xdr returned %d!\n", __func__, -status); return status; } @@ -3193,7 +3193,7 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons if ((status = verify_attr_len(xdr, savep, attrlen)) == 0) fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4; xdr_error: - dprintk("%s: xdr returned %d\n", __FUNCTION__, -status); + dprintk("%s: xdr returned %d\n", __func__, -status); return status; } @@ -3226,7 +3226,7 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) status = verify_attr_len(xdr, savep, attrlen); xdr_error: - dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status); + dprintk("%s: xdr returned %d!\n", __func__, -status); return status; } @@ -3418,7 +3418,7 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) return decode_delegation(xdr, res); xdr_error: - dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen); + dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen); return -EIO; } @@ -3575,7 +3575,7 @@ short_pkt: * the call was successful, but incomplete. The caller can retry the * readdir starting at the last cookie. */ - dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr); + dprintk("%s: short packet at entry %d\n", __func__, nr); entry[0] = entry[1] = 0; if (nr) goto out; diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 5ccf7faee19..03599bfe81c 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -63,17 +63,17 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, }; int status; - dprintk("%s: call getattr\n", __FUNCTION__); + dprintk("%s: call getattr\n", __func__); nfs_fattr_init(fattr); status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0); - dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); + dprintk("%s: reply getattr: %d\n", __func__, status); if (status) return status; - dprintk("%s: call statfs\n", __FUNCTION__); + dprintk("%s: call statfs\n", __func__); msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS]; msg.rpc_resp = &fsinfo; status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0); - dprintk("%s: reply statfs: %d\n", __FUNCTION__, status); + dprintk("%s: reply statfs: %d\n", __func__, status); if (status) return status; info->rtmax = NFS_MAXDATA; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 16f57e0af99..40d17987d0e 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -329,7 +329,7 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) { int status; - dprintk("NFS: %s: %5u, (status %d)\n", __FUNCTION__, task->tk_pid, + dprintk("NFS: %s: %5u, (status %d)\n", __func__, task->tk_pid, task->tk_status); status = NFS_PROTO(data->inode)->read_done(task, data); diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 5ed86ac0fd9..2a4a024a4e7 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -405,7 +405,7 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; out_err: - dprintk("%s: statfs error = %d\n", __FUNCTION__, -error); + dprintk("%s: statfs error = %d\n", __func__, -error); unlock_kernel(); return error; } -- cgit v1.2.3 From 31f31db1a15671513df9cd9fbe56ef45ee1e9a2a Mon Sep 17 00:00:00 2001 From: Jan Blunck Date: Fri, 2 May 2008 13:42:45 -0700 Subject: nfs: path_{get,put}() cleanups Here are some more places where path_{get,put}() can be used instead of dput()/mntput() pair. Signed-off-by: Jan Blunck Cc: Trond Myklebust Cc: "J. Bruce Fields" Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 3 +-- fs/nfs/namespace.c | 3 +-- fs/nfs/nfs4proc.c | 6 ++---- 3 files changed, 4 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 421d338c698..596c5d8e86f 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -541,8 +541,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) } if (ctx->cred != NULL) put_rpccred(ctx->cred); - dput(ctx->path.dentry); - mntput(ctx->path.mnt); + path_put(&ctx->path); kfree(ctx); } diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index fca518006a5..2f285ef7639 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -137,8 +137,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) goto out_follow; goto out_err; } - mntput(nd->path.mnt); - dput(nd->path.dentry); + path_put(&nd->path); nd->path.mnt = mnt; nd->path.dentry = dget(mnt->mnt_root); schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f533318b005..1293e0acd82 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -306,8 +306,7 @@ static void nfs4_opendata_free(struct kref *kref) nfs4_put_open_state(p->state); nfs4_put_state_owner(p->owner); dput(p->dir); - dput(p->path.dentry); - mntput(p->path.mnt); + path_put(&p->path); kfree(p); } @@ -1210,8 +1209,7 @@ static void nfs4_free_closedata(void *data) nfs4_put_open_state(calldata->state); nfs_free_seqid(calldata->arg.seqid); nfs4_put_state_owner(sp); - dput(calldata->path.dentry); - mntput(calldata->path.mnt); + path_put(&calldata->path); kfree(calldata); } -- cgit v1.2.3 From 1d2e88e73ee0af52b0ed63b5fb8f42a919a4d9de Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 2 May 2008 13:42:45 -0700 Subject: nfs: make nfs4_drop_state_owner() static nfs4_drop_state_owner() can now become static. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 1 - fs/nfs/nfs4state.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index bd1b9d663fb..ea790645fda 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -206,7 +206,6 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp); extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); extern void nfs4_put_state_owner(struct nfs4_state_owner *); -extern void nfs4_drop_state_owner(struct nfs4_state_owner *); extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); extern void nfs4_put_open_state(struct nfs4_state *); extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t); diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 5a1e02c8b75..856a8934f61 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -282,7 +282,7 @@ nfs4_alloc_state_owner(void) return sp; } -void +static void nfs4_drop_state_owner(struct nfs4_state_owner *sp) { if (!RB_EMPTY_NODE(&sp->so_client_node)) { -- cgit v1.2.3 From fec4585fd71cc5ec35d134e8c3854f6e8c4503f0 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 16 May 2008 13:06:30 +0400 Subject: CIFSGetDFSRefer cleanup + dfs_referral_level_3 fixed to conform REFERRAL_V3 the MS-DFSC spec. Signed-off-by: Igor Mammedov Signed-off-by: Steve French --- fs/cifs/cifspdu.h | 16 ++--- fs/cifs/cifssmb.c | 205 +++++++++++++++++++++++++++++++++++------------------- 2 files changed, 139 insertions(+), 82 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index c43bf4b7a55..93d5ee02a25 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1906,17 +1906,15 @@ typedef struct smb_com_transaction2_get_dfs_refer_req { typedef struct dfs_referral_level_3 { __le16 VersionNumber; - __le16 ReferralSize; - __le16 ServerType; /* 0x0001 = CIFS server */ - __le16 ReferralFlags; /* or proximity - not clear which since it is - always set to zero - SNIA spec says 0x01 - means strip off PathConsumed chars before - submitting RequestFileName to remote node */ - __le16 TimeToLive; - __le16 Proximity; + __le16 Size; + __le16 ServerType; /* 0x0001 = root targets; 0x0000 = link targets */ + __le16 ReferralEntryFlags; /* 0x0200 bit set only for domain + or DC referral responce */ + __le32 TimeToLive; __le16 DfsPathOffset; __le16 DfsAlternatePathOffset; - __le16 NetworkAddressOffset; + __le16 NetworkAddressOffset; /* offset of the link target */ + __le16 ServiceSiteGuid; } __attribute__((packed)) REFERRAL3; typedef struct smb_com_transaction_get_dfs_refer_rsp { diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index fc297383cb0..6f8ed93a4ae 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -81,6 +81,39 @@ static struct { #endif /* CONFIG_CIFS_WEAK_PW_HASH */ #endif /* CIFS_POSIX */ +/* Allocates buffer into dst and copies smb string from src to it. + * caller is responsible for freeing dst if function returned 0. + * returns: + * on success - 0 + * on failure - errno + */ +static int +cifs_strncpy_to_host(char **dst, const char *src, const int maxlen, + const bool is_unicode, const struct nls_table *nls_codepage) +{ + int plen; + + if (is_unicode) { + plen = UniStrnlen((wchar_t *)src, maxlen); + *dst = kmalloc(plen + 2, GFP_KERNEL); + if (!*dst) + goto cifs_strncpy_to_host_ErrExit; + cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage); + } else { + plen = strnlen(src, maxlen); + *dst = kmalloc(plen + 2, GFP_KERNEL); + if (!*dst) + goto cifs_strncpy_to_host_ErrExit; + strncpy(*dst, src, plen); + } + (*dst)[plen] = 0; + return 0; + +cifs_strncpy_to_host_ErrExit: + cERROR(1, ("Failed to allocate buffer for string\n")); + return -ENOMEM; +} + /* Mark as invalid, all open files on tree connections since they were closed when session to server was lost */ @@ -3867,6 +3900,96 @@ GetInodeNumOut: return rc; } +/* parses DFS refferal V3 structure + * caller is responsible for freeing target_nodes + * returns: + * on success - 0 + * on failure - errno + */ +static int +parse_DFS_REFERRALS(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, + unsigned int *num_of_nodes, + struct dfs_info3_param **target_nodes, + const struct nls_table *nls_codepage) +{ + int i, rc = 0; + char *data_end; + bool is_unicode; + struct dfs_referral_level_3 *ref; + + is_unicode = pSMBr->hdr.Flags2 & SMBFLG2_UNICODE; + *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals); + + if (*num_of_nodes < 1) { + cERROR(1, ("num_referrals: must be at least > 0," + "but we get num_referrals = %d\n", *num_of_nodes)); + rc = -EINVAL; + goto parse_DFS_REFERRALS_exit; + } + + ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals); + if (ref->VersionNumber != 3) { + cERROR(1, ("Referrals of V%d version are not supported," + "should be V3", ref->VersionNumber)); + rc = -EINVAL; + goto parse_DFS_REFERRALS_exit; + } + + /* get the upper boundary of the resp buffer */ + data_end = (char *)(&(pSMBr->PathConsumed)) + + le16_to_cpu(pSMBr->t2.DataCount); + + cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n", + *num_of_nodes, + le16_to_cpu(pSMBr->DFSFlags))); + + *target_nodes = kzalloc(sizeof(struct dfs_info3_param) * + *num_of_nodes, GFP_KERNEL); + if (*target_nodes == NULL) { + cERROR(1, ("Failed to allocate buffer for target_nodes\n")); + rc = -ENOMEM; + goto parse_DFS_REFERRALS_exit; + } + + /* collect neccessary data from referrals */ + for (i = 0; i < *num_of_nodes; i++) { + char *temp; + int max_len; + struct dfs_info3_param *node = (*target_nodes)+i; + + node->flags = le16_to_cpu(pSMBr->DFSFlags); + node->path_consumed = le16_to_cpu(pSMBr->PathConsumed); + node->server_type = le16_to_cpu(ref->ServerType); + node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); + + /* copy DfsPath */ + temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); + max_len = data_end - temp; + rc = cifs_strncpy_to_host(&(node->path_name), temp, + max_len, is_unicode, nls_codepage); + if (rc) + goto parse_DFS_REFERRALS_exit; + + /* copy link target UNC */ + temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); + max_len = data_end - temp; + rc = cifs_strncpy_to_host(&(node->node_name), temp, + max_len, is_unicode, nls_codepage); + if (rc) + goto parse_DFS_REFERRALS_exit; + + ref += ref->Size; + } + +parse_DFS_REFERRALS_exit: + if (rc) { + free_dfs_info_array(*target_nodes, *num_of_nodes); + *target_nodes = NULL; + *num_of_nodes = 0; + } + return rc; +} + int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, const unsigned char *searchName, @@ -3877,12 +4000,9 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, /* TRANS2_GET_DFS_REFERRAL */ TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; - struct dfs_referral_level_3 *referrals = NULL; int rc = 0; int bytes_returned; int name_len; - unsigned int i; - char *temp; __u16 params, byte_count; *num_of_nodes = 0; *target_nodes = NULL; @@ -3960,80 +4080,19 @@ getDFSRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); /* BB Also check if enough total bytes returned? */ - if (rc || (pSMBr->ByteCount < 17)) + if (rc || (pSMBr->ByteCount < 17)) { rc = -EIO; /* bad smb */ - else { - __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); - __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount); - - cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d", - pSMBr->ByteCount, data_offset)); - referrals = - (struct dfs_referral_level_3 *) - (8 /* sizeof start of data block */ + - data_offset + - (char *) &pSMBr->hdr.Protocol); - cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n" - "for referral one refer size: 0x%x srv " - "type: 0x%x refer flags: 0x%x ttl: 0x%x", - le16_to_cpu(pSMBr->NumberOfReferrals), - le16_to_cpu(pSMBr->DFSFlags), - le16_to_cpu(referrals->ReferralSize), - le16_to_cpu(referrals->ServerType), - le16_to_cpu(referrals->ReferralFlags), - le16_to_cpu(referrals->TimeToLive))); - /* BB This field is actually two bytes in from start of - data block so we could do safety check that DataBlock - begins at address of pSMBr->NumberOfReferrals */ - *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals); - - /* BB Fix below so can return more than one referral */ - if (*num_of_nodes > 1) - *num_of_nodes = 1; - - /* get the length of the strings describing refs */ - name_len = 0; - for (i = 0; i < *num_of_nodes; i++) { - /* make sure that DfsPathOffset not past end */ - __u16 offset = le16_to_cpu(referrals->DfsPathOffset); - if (offset > data_count) { - /* if invalid referral, stop here and do - not try to copy any more */ - *num_of_nodes = i; - break; - } - temp = ((char *)referrals) + offset; + goto GetDFSRefExit; + } - if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len += UniStrnlen((wchar_t *)temp, - data_count); - } else { - name_len += strnlen(temp, data_count); - } - referrals++; - /* BB add check that referral pointer does - not fall off end PDU */ - } - /* BB add check for name_len bigger than bcc */ - *target_nodes = - kmalloc(name_len+1+(*num_of_nodes), - GFP_KERNEL); - if (*target_nodes == NULL) { - rc = -ENOMEM; - goto GetDFSRefExit; - } + cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d", + pSMBr->ByteCount, + le16_to_cpu(pSMBr->t2.DataOffset))); - referrals = (struct dfs_referral_level_3 *) - (8 /* sizeof data hdr */ + data_offset + - (char *) &pSMBr->hdr.Protocol); + /* parse returned result into more usable form */ + rc = parse_DFS_REFERRALS(pSMBr, num_of_nodes, + target_nodes, nls_codepage); - for (i = 0; i < *num_of_nodes; i++) { - temp = ((char *)referrals) + - le16_to_cpu(referrals->DfsPathOffset); - /* BB update target_uncs pointers */ - referrals++; - } - } GetDFSRefExit: if (pSMB) cifs_buf_release(pSMB); -- cgit v1.2.3 From a1fe78f16eac7d03d3c391dd5d54559826574982 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 16 May 2008 18:48:38 +0000 Subject: [CIFS] Add missing defines for DFS Also has minor cleanup of previous patch CC: Igor Mammedov Signed-off-by: Steve French --- fs/cifs/cifspdu.h | 9 +++++++++ fs/cifs/cifssmb.c | 17 +++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 93d5ee02a25..65d58b4e6a6 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1904,6 +1904,15 @@ typedef struct smb_com_transaction2_get_dfs_refer_req { char RequestFileName[1]; } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ; +#define DFS_VERSION cpu_to_le16(0x0003) + +/* DFS server target type */ +#define DFS_TYPE_LINK 0x0000 /* also for sysvol targets */ +#define DFS_TYPE_ROOT 0x0001 + +/* Referral Entry Flags */ +#define DFS_NAME_LIST_REF 0x0200 + typedef struct dfs_referral_level_3 { __le16 VersionNumber; __le16 Size; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6f8ed93a4ae..7b9938445b0 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -107,6 +107,7 @@ cifs_strncpy_to_host(char **dst, const char *src, const int maxlen, strncpy(*dst, src, plen); } (*dst)[plen] = 0; + (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */ return 0; cifs_strncpy_to_host_ErrExit: @@ -3907,7 +3908,7 @@ GetInodeNumOut: * on failure - errno */ static int -parse_DFS_REFERRALS(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, +parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, unsigned int *num_of_nodes, struct dfs_info3_param **target_nodes, const struct nls_table *nls_codepage) @@ -3924,7 +3925,7 @@ parse_DFS_REFERRALS(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, cERROR(1, ("num_referrals: must be at least > 0," "but we get num_referrals = %d\n", *num_of_nodes)); rc = -EINVAL; - goto parse_DFS_REFERRALS_exit; + goto parse_DFS_referrals_exit; } ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals); @@ -3932,7 +3933,7 @@ parse_DFS_REFERRALS(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, cERROR(1, ("Referrals of V%d version are not supported," "should be V3", ref->VersionNumber)); rc = -EINVAL; - goto parse_DFS_REFERRALS_exit; + goto parse_DFS_referrals_exit; } /* get the upper boundary of the resp buffer */ @@ -3948,7 +3949,7 @@ parse_DFS_REFERRALS(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, if (*target_nodes == NULL) { cERROR(1, ("Failed to allocate buffer for target_nodes\n")); rc = -ENOMEM; - goto parse_DFS_REFERRALS_exit; + goto parse_DFS_referrals_exit; } /* collect neccessary data from referrals */ @@ -3968,7 +3969,7 @@ parse_DFS_REFERRALS(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, rc = cifs_strncpy_to_host(&(node->path_name), temp, max_len, is_unicode, nls_codepage); if (rc) - goto parse_DFS_REFERRALS_exit; + goto parse_DFS_referrals_exit; /* copy link target UNC */ temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); @@ -3976,12 +3977,12 @@ parse_DFS_REFERRALS(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, rc = cifs_strncpy_to_host(&(node->node_name), temp, max_len, is_unicode, nls_codepage); if (rc) - goto parse_DFS_REFERRALS_exit; + goto parse_DFS_referrals_exit; ref += ref->Size; } -parse_DFS_REFERRALS_exit: +parse_DFS_referrals_exit: if (rc) { free_dfs_info_array(*target_nodes, *num_of_nodes); *target_nodes = NULL; @@ -4090,7 +4091,7 @@ getDFSRetry: le16_to_cpu(pSMBr->t2.DataOffset))); /* parse returned result into more usable form */ - rc = parse_DFS_REFERRALS(pSMBr, num_of_nodes, + rc = parse_DFS_referrals(pSMBr, num_of_nodes, target_nodes, nls_codepage); GetDFSRefExit: -- cgit v1.2.3 From 9a6ab769bdacc65e7d4e931034e12e02c357c4d3 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Fri, 16 May 2008 11:20:25 -0700 Subject: byteorder: don't directly include linux/byteorder/generic.h Use asm/byteorder.h instead. Signed-off-by: Harvey Harrison Signed-off-by: Linus Torvalds --- fs/befs/endian.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/befs/endian.h b/fs/befs/endian.h index e254a20869f..6cb84d896d0 100644 --- a/fs/befs/endian.h +++ b/fs/befs/endian.h @@ -9,7 +9,7 @@ #ifndef LINUX_BEFS_ENDIAN #define LINUX_BEFS_ENDIAN -#include +#include static inline u64 fs64_to_cpu(const struct super_block *sb, fs64 n) -- cgit v1.2.3 From f52111b1546943545e67573c4dde1c7613ca33d3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 8 May 2008 18:19:16 -0400 Subject: [PATCH] take init_files to fs/file.c Signed-off-by: Al Viro --- fs/file.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'fs') diff --git a/fs/file.c b/fs/file.c index 4c6f0ea12c4..754cd05b06a 100644 --- a/fs/file.c +++ b/fs/file.c @@ -275,3 +275,16 @@ void __init files_defer_init(void) for_each_possible_cpu(i) fdtable_defer_list_init(i); } + +struct files_struct init_files = { + .count = ATOMIC_INIT(1), + .fdt = &init_files.fdtab, + .fdtab = { + .max_fds = NR_OPEN_DEFAULT, + .fd = &init_files.fd_array[0], + .close_on_exec = (fd_set *)&init_files.close_on_exec_init, + .open_fds = (fd_set *)&init_files.open_fds_init, + .rcu = RCU_HEAD_INIT, + }, + .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), +}; -- cgit v1.2.3 From 02afc6267f6d55d47aba9fcafdbd1b7230d2294a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 8 May 2008 19:42:56 -0400 Subject: [PATCH] dup_fd() fixes, part 1 Move the sucker to fs/file.c in preparation to the rest Signed-off-by: Al Viro --- fs/file.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) (limited to 'fs') diff --git a/fs/file.c b/fs/file.c index 754cd05b06a..7dbadaaf00f 100644 --- a/fs/file.c +++ b/fs/file.c @@ -261,6 +261,136 @@ int expand_files(struct files_struct *files, int nr) return expand_fdtable(files, nr); } +static int count_open_files(struct fdtable *fdt) +{ + int size = fdt->max_fds; + int i; + + /* Find the last open fd */ + for (i = size/(8*sizeof(long)); i > 0; ) { + if (fdt->open_fds->fds_bits[--i]) + break; + } + i = (i+1) * 8 * sizeof(long); + return i; +} + +static struct files_struct *alloc_files(void) +{ + struct files_struct *newf; + struct fdtable *fdt; + + newf = kmem_cache_alloc(files_cachep, GFP_KERNEL); + if (!newf) + goto out; + + atomic_set(&newf->count, 1); + + spin_lock_init(&newf->file_lock); + newf->next_fd = 0; + fdt = &newf->fdtab; + fdt->max_fds = NR_OPEN_DEFAULT; + fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init; + fdt->open_fds = (fd_set *)&newf->open_fds_init; + fdt->fd = &newf->fd_array[0]; + INIT_RCU_HEAD(&fdt->rcu); + fdt->next = NULL; + rcu_assign_pointer(newf->fdt, fdt); +out: + return newf; +} + +/* + * Allocate a new files structure and copy contents from the + * passed in files structure. + * errorp will be valid only when the returned files_struct is NULL. + */ +struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) +{ + struct files_struct *newf; + struct file **old_fds, **new_fds; + int open_files, size, i; + struct fdtable *old_fdt, *new_fdt; + + *errorp = -ENOMEM; + newf = alloc_files(); + if (!newf) + goto out; + + spin_lock(&oldf->file_lock); + old_fdt = files_fdtable(oldf); + new_fdt = files_fdtable(newf); + open_files = count_open_files(old_fdt); + + /* + * Check whether we need to allocate a larger fd array and fd set. + * Note: we're not a clone task, so the open count won't change. + */ + if (open_files > new_fdt->max_fds) { + new_fdt->max_fds = 0; + spin_unlock(&oldf->file_lock); + spin_lock(&newf->file_lock); + *errorp = expand_files(newf, open_files-1); + spin_unlock(&newf->file_lock); + if (*errorp < 0) + goto out_release; + new_fdt = files_fdtable(newf); + /* + * Reacquire the oldf lock and a pointer to its fd table + * who knows it may have a new bigger fd table. We need + * the latest pointer. + */ + spin_lock(&oldf->file_lock); + old_fdt = files_fdtable(oldf); + } + + old_fds = old_fdt->fd; + new_fds = new_fdt->fd; + + memcpy(new_fdt->open_fds->fds_bits, + old_fdt->open_fds->fds_bits, open_files/8); + memcpy(new_fdt->close_on_exec->fds_bits, + old_fdt->close_on_exec->fds_bits, open_files/8); + + for (i = open_files; i != 0; i--) { + struct file *f = *old_fds++; + if (f) { + get_file(f); + } else { + /* + * The fd may be claimed in the fd bitmap but not yet + * instantiated in the files array if a sibling thread + * is partway through open(). So make sure that this + * fd is available to the new process. + */ + FD_CLR(open_files - i, new_fdt->open_fds); + } + rcu_assign_pointer(*new_fds++, f); + } + spin_unlock(&oldf->file_lock); + + /* compute the remainder to be cleared */ + size = (new_fdt->max_fds - open_files) * sizeof(struct file *); + + /* This is long word aligned thus could use a optimized version */ + memset(new_fds, 0, size); + + if (new_fdt->max_fds > open_files) { + int left = (new_fdt->max_fds-open_files)/8; + int start = open_files / (8 * sizeof(unsigned long)); + + memset(&new_fdt->open_fds->fds_bits[start], 0, left); + memset(&new_fdt->close_on_exec->fds_bits[start], 0, left); + } + + return newf; + +out_release: + kmem_cache_free(files_cachep, newf); +out: + return NULL; +} + static void __devinit fdtable_defer_list_init(int cpu) { struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu); -- cgit v1.2.3 From 9dec3c4d306b09b31331e475e895bb9674e16d81 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 8 May 2008 21:02:45 -0400 Subject: [PATCH] dup_fd() part 2 use alloc_fdtable() instead of expand_files(), get rid of pointless grabbing newf->file_lock, kill magic in copy_fdtable() that used to be there only to skip copying when called from dup_fd(). Signed-off-by: Al Viro --- fs/file.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/file.c b/fs/file.c index 7dbadaaf00f..6491b2b5bc3 100644 --- a/fs/file.c +++ b/fs/file.c @@ -119,8 +119,6 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt) unsigned int cpy, set; BUG_ON(nfdt->max_fds < ofdt->max_fds); - if (ofdt->max_fds == 0) - return; cpy = ofdt->max_fds * sizeof(struct file *); set = (nfdt->max_fds - ofdt->max_fds) * sizeof(struct file *); @@ -327,14 +325,24 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) * Note: we're not a clone task, so the open count won't change. */ if (open_files > new_fdt->max_fds) { - new_fdt->max_fds = 0; spin_unlock(&oldf->file_lock); - spin_lock(&newf->file_lock); - *errorp = expand_files(newf, open_files-1); - spin_unlock(&newf->file_lock); - if (*errorp < 0) + + new_fdt = alloc_fdtable(open_files - 1); + if (!new_fdt) { + *errorp = -ENOMEM; + goto out_release; + } + + /* beyond sysctl_nr_open; nothing to do */ + if (unlikely(new_fdt->max_fds < open_files)) { + free_fdarr(new_fdt); + free_fdset(new_fdt); + kfree(new_fdt); + *errorp = -EMFILE; goto out_release; - new_fdt = files_fdtable(newf); + } + rcu_assign_pointer(files->fdt, new_fdt); + /* * Reacquire the oldf lock and a pointer to its fd table * who knows it may have a new bigger fd table. We need -- cgit v1.2.3 From afbec7fff4928c273a1f1bb14dfdfdf62688a193 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 8 May 2008 21:11:17 -0400 Subject: [PATCH] dup_fd() - part 3 merge alloc_files() into dup_fd(), leave setting newf->fdt until the end Signed-off-by: Al Viro --- fs/file.c | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) (limited to 'fs') diff --git a/fs/file.c b/fs/file.c index 6491b2b5bc3..689d2b6947e 100644 --- a/fs/file.c +++ b/fs/file.c @@ -273,31 +273,6 @@ static int count_open_files(struct fdtable *fdt) return i; } -static struct files_struct *alloc_files(void) -{ - struct files_struct *newf; - struct fdtable *fdt; - - newf = kmem_cache_alloc(files_cachep, GFP_KERNEL); - if (!newf) - goto out; - - atomic_set(&newf->count, 1); - - spin_lock_init(&newf->file_lock); - newf->next_fd = 0; - fdt = &newf->fdtab; - fdt->max_fds = NR_OPEN_DEFAULT; - fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init; - fdt->open_fds = (fd_set *)&newf->open_fds_init; - fdt->fd = &newf->fd_array[0]; - INIT_RCU_HEAD(&fdt->rcu); - fdt->next = NULL; - rcu_assign_pointer(newf->fdt, fdt); -out: - return newf; -} - /* * Allocate a new files structure and copy contents from the * passed in files structure. @@ -311,13 +286,24 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) struct fdtable *old_fdt, *new_fdt; *errorp = -ENOMEM; - newf = alloc_files(); + newf = kmem_cache_alloc(files_cachep, GFP_KERNEL); if (!newf) goto out; + atomic_set(&newf->count, 1); + + spin_lock_init(&newf->file_lock); + newf->next_fd = 0; + new_fdt = &newf->fdtab; + new_fdt->max_fds = NR_OPEN_DEFAULT; + new_fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init; + new_fdt->open_fds = (fd_set *)&newf->open_fds_init; + new_fdt->fd = &newf->fd_array[0]; + INIT_RCU_HEAD(&new_fdt->rcu); + new_fdt->next = NULL; + spin_lock(&oldf->file_lock); old_fdt = files_fdtable(oldf); - new_fdt = files_fdtable(newf); open_files = count_open_files(old_fdt); /* @@ -341,7 +327,6 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) *errorp = -EMFILE; goto out_release; } - rcu_assign_pointer(files->fdt, new_fdt); /* * Reacquire the oldf lock and a pointer to its fd table @@ -391,6 +376,8 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) memset(&new_fdt->close_on_exec->fds_bits[start], 0, left); } + rcu_assign_pointer(newf->fdt, new_fdt); + return newf; out_release: -- cgit v1.2.3 From adbecb128cd2cc5d14b0ebef6d020ced0efd0ec6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 8 May 2008 21:19:42 -0400 Subject: [PATCH] dup_fd() part 4 - race fix Parent _can_ be a clone task, contrary to the comment. Moreover, more files could be opened while we allocate a copy, in which case we end up copying only part into new descriptor table. Since what we get _is_ affected by all changes in the old range, we can get rather weird effects - e.g. dup2(0, 1024); close(0); in parallel with fork() resulting in child that sees the effect of close(), but not that of dup2() done just before that close(). What we need is to recalculate the open_count after having reacquired ->file_lock and if external fdtable we'd just allocated is too small for it, free the sucker and redo allocation. Signed-off-by: Al Viro --- fs/file.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/file.c b/fs/file.c index 689d2b6947e..0f705c7cfef 100644 --- a/fs/file.c +++ b/fs/file.c @@ -308,11 +308,16 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) /* * Check whether we need to allocate a larger fd array and fd set. - * Note: we're not a clone task, so the open count won't change. */ - if (open_files > new_fdt->max_fds) { + while (unlikely(open_files > new_fdt->max_fds)) { spin_unlock(&oldf->file_lock); + if (new_fdt != &newf->fdtab) { + free_fdarr(new_fdt); + free_fdset(new_fdt); + kfree(new_fdt); + } + new_fdt = alloc_fdtable(open_files - 1); if (!new_fdt) { *errorp = -ENOMEM; @@ -335,6 +340,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) */ spin_lock(&oldf->file_lock); old_fdt = files_fdtable(oldf); + open_files = count_open_files(old_fdt); } old_fds = old_fdt->fd; -- cgit v1.2.3 From eceea0b3df05ed262ae32e0c6340cc7a3626632d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 10 May 2008 10:08:32 -0400 Subject: [PATCH] avoid multiplication overflows and signedness issues for max_fds Limit sysctl_nr_open - we don't want ->max_fds to exceed MAX_INT and we don't want size calculation for ->fd[] to overflow. Signed-off-by: Al Viro --- fs/file.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs') diff --git a/fs/file.c b/fs/file.c index 0f705c7cfef..7b3887e054d 100644 --- a/fs/file.c +++ b/fs/file.c @@ -26,6 +26,8 @@ struct fdtable_defer { }; int sysctl_nr_open __read_mostly = 1024*1024; +int sysctl_nr_open_min = BITS_PER_LONG; +int sysctl_nr_open_max = 1024 * 1024; /* raised later */ /* * We use this list to defer free fdtables that have vmalloced @@ -405,6 +407,8 @@ void __init files_defer_init(void) int i; for_each_possible_cpu(i) fdtable_defer_list_init(i); + sysctl_nr_open_max = min((size_t)INT_MAX, ~(size_t)0/sizeof(void *)) & + -BITS_PER_LONG; } struct files_struct init_files = { -- cgit v1.2.3 From 5f719558edf9c84bfbb1f7ad37e84c483282d09f Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Tue, 6 May 2008 12:45:35 +0800 Subject: [Patch] fs/binfmt_elf.c: fix a wrong free In kmalloc failing path, we shouldn't free pointers in 'info', because the struct 'info' is uninitilized when kmalloc is called. And when kmalloc returns NULL, it's needless to kfree it. Signed-off-by: WANG Cong Cc: Alexander Viro Reviewed-by: Pekka Enberg -- Signed-off-by: Al Viro --- fs/binfmt_elf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index b25707fee2c..bd08332079c 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1900,7 +1900,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un /* alloc memory for large data structures: too large to be on stack */ elf = kmalloc(sizeof(*elf), GFP_KERNEL); if (!elf) - goto cleanup; + goto out; segs = current->mm->map_count; #ifdef ELF_CORE_EXTRA_PHDRS @@ -2034,8 +2034,9 @@ end_coredump: set_fs(fs); cleanup: - kfree(elf); free_note_info(&info); + kfree(elf); +out: return has_dumped; } -- cgit v1.2.3 From 08a6fac1c63233c87eec129938022f1a9a4d51f6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 10 May 2008 16:38:25 -0400 Subject: [PATCH] get rid of leak in compat_execve() Even though copy_compat_strings() doesn't cache the pages, copy_strings_kernel() and stuff indirectly called by e.g. ->load_binary() is doing that, so we need to drop the cache contents in the end. [found by WANG Cong ] Signed-off-by: Al Viro --- fs/compat.c | 4 ++-- fs/exec.c | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/compat.c b/fs/compat.c index 332a869d2c5..ed43e17a5dc 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1405,7 +1405,7 @@ int compat_do_execve(char * filename, /* execve success */ security_bprm_free(bprm); acct_update_integrals(current); - kfree(bprm); + free_bprm(bprm); return retval; } @@ -1424,7 +1424,7 @@ out_file: } out_kfree: - kfree(bprm); + free_bprm(bprm); out_ret: return retval; diff --git a/fs/exec.c b/fs/exec.c index 1f8a24aa1f8..3c2ba7ce11d 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1251,6 +1251,12 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) EXPORT_SYMBOL(search_binary_handler); +void free_bprm(struct linux_binprm *bprm) +{ + free_arg_pages(bprm); + kfree(bprm); +} + /* * sys_execve() executes a new program. */ @@ -1320,17 +1326,15 @@ int do_execve(char * filename, retval = search_binary_handler(bprm,regs); if (retval >= 0) { /* execve success */ - free_arg_pages(bprm); security_bprm_free(bprm); acct_update_integrals(current); - kfree(bprm); + free_bprm(bprm); if (displaced) put_files_struct(displaced); return retval; } out: - free_arg_pages(bprm); if (bprm->security) security_bprm_free(bprm); @@ -1344,7 +1348,7 @@ out_file: fput(bprm->file); } out_kfree: - kfree(bprm); + free_bprm(bprm); out_files: if (displaced) -- cgit v1.2.3 From 23c4971e3d97de4e1b7961ca6eacee35aa15ce5f Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Thu, 8 May 2008 21:52:33 +0800 Subject: [Patch] fs/binfmt_elf.c: fix wrong return values create_elf_tables() returns 0 on success. But when strnlen_user() "fails", it returns 0 directly. So this is wrong. Signed-off-by: WANG Cong Cc: Alexander Viro Signed-off-by: Al Viro --- fs/binfmt_elf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index bd08332079c..0fa95b198e6 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -256,7 +256,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, return -EFAULT; len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); if (!len || len > MAX_ARG_STRLEN) - return 0; + return -EINVAL; p += len; } if (__put_user(0, argv)) @@ -268,7 +268,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, return -EFAULT; len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); if (!len || len > MAX_ARG_STRLEN) - return 0; + return -EINVAL; p += len; } if (__put_user(0, envp)) -- cgit v1.2.3 From e9baf6e59842285bcf9570f5094e4c27674a0f7c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 15 May 2008 04:49:12 -0400 Subject: [PATCH] return to old errno choice in mkdir() et.al. In case when both EEXIST and EROFS would apply we used to return the former in mkdir(2) and friends. Lest anyone suspects us of being consistent, in the same situation knfsd gave clients nfs_erofs... ro-bind series had switched the syscall side of things to returning -EROFS and immediately broke an application - namely, mkdir -p. Patch restores the original behaviour... Signed-off-by: Al Viro --- fs/namei.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 32fd9655485..c7e43536c49 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2003,18 +2003,22 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir) if (IS_ERR(dentry)) goto fail; + if (dentry->d_inode) + goto eexist; /* * Special case - lookup gave negative, but... we had foo/bar/ * From the vfs_mknod() POV we just have a negative dentry - * all is fine. Let's be bastards - you had / on the end, you've * been asking for (non-existent) directory. -ENOENT for you. */ - if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode) - goto enoent; + if (unlikely(!is_dir && nd->last.name[nd->last.len])) { + dput(dentry); + dentry = ERR_PTR(-ENOENT); + } return dentry; -enoent: +eexist: dput(dentry); - dentry = ERR_PTR(-ENOENT); + dentry = ERR_PTR(-EEXIST); fail: return dentry; } -- cgit v1.2.3 From 2b280fab12b6697b6a7a24a13aaf9f4339edd075 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 17 May 2008 03:12:45 +0000 Subject: [CIFS] add more complete mount options to cifs_show_options adds various options to cifs_show_options (displayed when you cat /proc/mounts with a cifs mount). I limited the new ones to values that are associated with the mount with the exception of "seal" (which is a per tree connection property, but I thought was important enough to show through). Eventually cifs's parse_mount_options also needs to be rewritten to use the match_token API but that would be a big enough change that I would prefer that changing parse_mount_options wait until next release. Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index b6436b888cf..57e40c49d3b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1,7 +1,7 @@ /* * fs/cifs/cifsfs.c * - * Copyright (C) International Business Machines Corp., 2002,2007 + * Copyright (C) International Business Machines Corp., 2002,2008 * Author(s): Steve French (sfrench@us.ibm.com) * * Common Internet FileSystem (CIFS) client @@ -353,9 +353,38 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || !(cifs_sb->tcon->unix_ext)) seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); + if (!cifs_sb->tcon->unix_ext) { + seq_printf(s, ",file_mode=0%o,dir_mode=0%o", + cifs_sb->mnt_file_mode, + cifs_sb->mnt_dir_mode); + } + if (cifs_sb->tcon->seal) + seq_printf(s, ",seal"); + seq_printf(s, ",nocase"); } if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) seq_printf(s, ",posixpaths"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) + seq_printf(s, ",setuids"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) + seq_printf(s, ",serverino"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) + seq_printf(s, ",directio"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) + seq_printf(s, ",nouser_xattr"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) + seq_printf(s, ",mapchars"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) + seq_printf(s, ",sfu"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + seq_printf(s, ",nobrl"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) + seq_printf(s, ",cifsacl"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) + seq_printf(s, ",dynperm"); + if (m->mnt_sb->s_flags & MS_POSIXACL) + seq_printf(s, ",acl"); + seq_printf(s, ",rsize=%d", cifs_sb->rsize); seq_printf(s, ",wsize=%d", cifs_sb->wsize); } -- cgit v1.2.3 From 6ee650467d5bf972d10441e99688e9b48171f99c Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Tue, 29 Apr 2008 15:01:13 -0400 Subject: [PATCH] open sessionid permissions The current permissions on sessionid are a little too restrictive. Signed-off-by: Steve Grubb Signed-off-by: Al Viro --- fs/proc/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/proc/base.c b/fs/proc/base.c index 808cbdc193d..c447e0743a3 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2441,7 +2441,7 @@ static const struct pid_entry tgid_base_stuff[] = { REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust), #ifdef CONFIG_AUDITSYSCALL REG("loginuid", S_IWUSR|S_IRUGO, loginuid), - REG("sessionid", S_IRUSR, sessionid), + REG("sessionid", S_IRUGO, sessionid), #endif #ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject), -- cgit v1.2.3 From 88dd0be3874566796fa4ffbdf927a53c4a6a2f4b Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 5 May 2008 19:47:29 -0400 Subject: nfsd: reorder printk in do_probe_callback to avoid use-after-free We're currently dereferencing the client after we drop our reference count to it. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 0b3ffa9840c..4d4760e687c 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -419,9 +419,9 @@ static int do_probe_callback(void *data) out_release_client: rpc_shutdown_client(client); out_err: - put_nfs4_client(clp); dprintk("NFSD: warning: no callback path to client %.*s\n", (int)clp->cl_name.len, clp->cl_name.data); + put_nfs4_client(clp); return status; } -- cgit v1.2.3 From 7a936ce71eed7b887b8a0d6c54dd8a9072f71c9f Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 12 May 2008 10:04:51 -0500 Subject: dlm: convert connections_lock in a mutex The semaphore connections_lock is used as a mutex. Convert it to the mutex API. Signed-off-by: Matthias Kaehlcke Cc: Christine Caulfield Cc: David Teigland Cc: Steven Whitehouse Signed-off-by: Andrew Morton Signed-off-by: David Teigland --- fs/dlm/lowcomms.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 7c1e5e5cccd..c7d232a9ae1 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -138,7 +139,7 @@ static struct workqueue_struct *recv_workqueue; static struct workqueue_struct *send_workqueue; static DEFINE_IDR(connections_idr); -static DECLARE_MUTEX(connections_lock); +static DEFINE_MUTEX(connections_lock); static int max_nodeid; static struct kmem_cache *con_cache; @@ -205,9 +206,9 @@ static struct connection *nodeid2con(int nodeid, gfp_t allocation) { struct connection *con; - down(&connections_lock); + mutex_lock(&connections_lock); con = __nodeid2con(nodeid, allocation); - up(&connections_lock); + mutex_unlock(&connections_lock); return con; } @@ -218,15 +219,15 @@ static struct connection *assoc2con(int assoc_id) int i; struct connection *con; - down(&connections_lock); + mutex_lock(&connections_lock); for (i=0; i<=max_nodeid; i++) { con = __nodeid2con(i, 0); if (con && con->sctp_assoc == assoc_id) { - up(&connections_lock); + mutex_unlock(&connections_lock); return con; } } - up(&connections_lock); + mutex_unlock(&connections_lock); return NULL; } @@ -381,7 +382,7 @@ static void sctp_init_failed(void) int i; struct connection *con; - down(&connections_lock); + mutex_lock(&connections_lock); for (i=1; i<=max_nodeid; i++) { con = __nodeid2con(i, 0); if (!con) @@ -393,7 +394,7 @@ static void sctp_init_failed(void) } } } - up(&connections_lock); + mutex_unlock(&connections_lock); } /* Something happened to an association */ @@ -1417,7 +1418,7 @@ void dlm_lowcomms_stop(void) /* Set all the flags to prevent any socket activity. */ - down(&connections_lock); + mutex_lock(&connections_lock); for (i = 0; i <= max_nodeid; i++) { con = __nodeid2con(i, 0); if (con) { @@ -1426,11 +1427,11 @@ void dlm_lowcomms_stop(void) con->sock->sk->sk_user_data = NULL; } } - up(&connections_lock); + mutex_unlock(&connections_lock); work_stop(); - down(&connections_lock); + mutex_lock(&connections_lock); clean_writequeues(); for (i = 0; i <= max_nodeid; i++) { @@ -1443,7 +1444,7 @@ void dlm_lowcomms_stop(void) } } max_nodeid = 0; - up(&connections_lock); + mutex_unlock(&connections_lock); kmem_cache_destroy(con_cache); idr_init(&connections_idr); } -- cgit v1.2.3 From 88ad23195e4609cef73b6fcf2b4c08aaaef33204 Mon Sep 17 00:00:00 2001 From: Leonardo Potenza Date: Sun, 11 May 2008 19:15:34 +0200 Subject: dlm: section mismatch warning fix Removed the section mismatch message: WARNING: fs/dlm/dlm.o(.init.text+0x132): Section mismatch in reference from the function init_module() to the function .exit.text:dlm_netlink_exit() Since dlm_netlink_exit() is called in the init_dlm() error handling, the __exit annotation has been removed. Signed-off-by: Leonardo Potenza Signed-off-by: David Teigland --- fs/dlm/netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c index 714593621f4..18bda83cc89 100644 --- a/fs/dlm/netlink.c +++ b/fs/dlm/netlink.c @@ -95,7 +95,7 @@ int __init dlm_netlink_init(void) return rv; } -void __exit dlm_netlink_exit(void) +void dlm_netlink_exit(void) { genl_unregister_ops(&family, &dlm_nl_ops); genl_unregister_family(&family); -- cgit v1.2.3 From 0035a4b14931eb62a5f8a7762284c18e7ab14289 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 11 May 2008 22:01:29 +0200 Subject: dlm: tcp_connect_to_sock should check for -EINVAL, not EINVAL Signed-off-by: Marcin Slusarz Cc: Christine Caulfield Cc: David Teigland Cc: cluster-devel@redhat.com Signed-off-by: David Teigland --- fs/dlm/lowcomms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index c7d232a9ae1..637018c891e 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -931,7 +931,7 @@ out_err: * errors we try again until the max number of retries is reached. */ if (result != -EHOSTUNREACH && result != -ENETUNREACH && - result != -ENETDOWN && result != EINVAL + result != -ENETDOWN && result != -EINVAL && result != -EPROTONOSUPPORT) { lowcomms_connect_sock(con); result = 0; -- cgit v1.2.3 From 817d10bad56f2fdfa321b4a864a21295226b123a Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 13 May 2008 14:28:26 -0500 Subject: dlm: fix plock dev_write return value The return value on writes to the plock device should be the number of bytes written. It was returning 0 instead when an nfs lock callback was involved. Reported-by: Nathan Straz Signed-off-by: David Teigland --- fs/dlm/plock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index d6d6e370f89..78878c5781c 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c @@ -379,7 +379,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, struct plock_xop *xop; xop = (struct plock_xop *)op; if (xop->callback) - count = dlm_plock_callback(op); + dlm_plock_callback(op); else wake_up(&recv_wq); } else -- cgit v1.2.3 From 89562b777c50d100d1694db7b1b023279839b9ae Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 19 May 2008 22:26:42 +0000 Subject: [CIFS] add missing seq_printf to cifs_show_options for hard mount option Also Kari Hurtta noticed a missing check in the same function which is now fixed. CC: Kari Hurtta Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 57e40c49d3b..5df93fd6303 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -360,7 +360,10 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) } if (cifs_sb->tcon->seal) seq_printf(s, ",seal"); + if (cifs_sb->tcon->nocase) seq_printf(s, ",nocase"); + if (cifs_sb->tcon->retry) + seq_printf(s, ",hard"); } if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) seq_printf(s, ",posixpaths"); -- cgit v1.2.3 From 0e4bbde94fdc33f5b3d793166b21bf768ca3e098 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 20 May 2008 19:50:46 +0000 Subject: [CIFS] Enable DFS support for Unix query path info Final piece for handling DFS in unix_query_path_info, constructing a fake inode for the junction directory which the submount will cover. Acked-by: Igor Mammedov Signed-off-by: Steve French --- fs/cifs/AUTHORS | 1 + fs/cifs/CHANGES | 2 + fs/cifs/TODO | 15 ++++---- fs/cifs/inode.c | 117 +++++++++++++++++++++++++++++++++++--------------------- 4 files changed, 85 insertions(+), 50 deletions(-) (limited to 'fs') diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS index 8848e4dfa02..9c136d7803d 100644 --- a/fs/cifs/AUTHORS +++ b/fs/cifs/AUTHORS @@ -36,6 +36,7 @@ Miklos Szeredi Kazeon team for various fixes especially for 2.4 version. Asser Ferno (Change Notify support) Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup +Igor Mammedov (DFS support) Test case and Bug Report contributors ------------------------------------- diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 502a4c2b841..28e3d5c5fca 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,5 +1,7 @@ Version 1.53 ------------ +DFS support added (Microsoft Distributed File System client support needed +for referrals which enable a hierarchical name space among servers). Version 1.52 ------------ diff --git a/fs/cifs/TODO b/fs/cifs/TODO index 92c9feac440..5aff46c61e5 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -1,4 +1,4 @@ -Version 1.52 January 3, 2008 +Version 1.53 May 20, 2008 A Partial List of Missing Features ================================== @@ -20,20 +20,21 @@ d) Cleanup now unneeded SessSetup code in fs/cifs/connect.c and add back in NTLMSSP code if any servers need it -e) ms-dfs and ms-dfs host name resolution cleanup - -f) fix NTLMv2 signing when two mounts with different users to same +e) fix NTLMv2 signing when two mounts with different users to same server. -g) Directory entry caching relies on a 1 second timer, rather than +f) Directory entry caching relies on a 1 second timer, rather than using FindNotify or equivalent. - (started) -h) quota support (needs minor kernel change since quota calls +g) quota support (needs minor kernel change since quota calls to make it to network filesystems or deviceless filesystems) -i) investigate sync behavior (including syncpage) and check +h) investigate sync behavior (including syncpage) and check for proper behavior of intr/nointr +i) improve support for very old servers (OS/2 and Win9x for example) +Including support for changing the time remotely (utimes command). + j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the extra copy in/out of the socket buffers in some cases. diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 9d9b56a9c08..422d4e219fa 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -161,77 +161,108 @@ static void cifs_unix_info_to_inode(struct inode *inode, spin_unlock(&inode->i_lock); } +static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat, + struct super_block *sb) +{ + struct inode *pinode = NULL; + + memset(pfnd_dat, sizeof(FILE_UNIX_BASIC_INFO), 0); + +/* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0); + __le64 pfnd_dat->NumOfBytes = cpu_to_le64(0); + __u64 UniqueId = 0; */ + pfnd_dat->LastStatusChange = + cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + pfnd_dat->LastAccessTime = + cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + pfnd_dat->LastModificationTime = + cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + pfnd_dat->Type = cpu_to_le32(UNIX_DIR); + pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU); + pfnd_dat->Nlinks = cpu_to_le64(2); + if (sb->s_root) + pinode = sb->s_root->d_inode; + if (pinode == NULL) + return; + + /* fill in default values for the remaining based on root + inode since we can not query the server for this inode info */ + pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev)); + pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev)); + pfnd_dat->Uid = cpu_to_le64(pinode->i_uid); + pfnd_dat->Gid = cpu_to_le64(pinode->i_gid); +} + int cifs_get_inode_info_unix(struct inode **pinode, const unsigned char *full_path, struct super_block *sb, int xid) { int rc = 0; - FILE_UNIX_BASIC_INFO findData; + FILE_UNIX_BASIC_INFO find_data; struct cifsTconInfo *pTcon; struct inode *inode; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); bool is_dfs_referral = false; + struct cifsInodeInfo *cifsInfo; + __u64 num_of_bytes; + __u64 end_of_file; pTcon = cifs_sb->tcon; cFYI(1, ("Getting info on %s", full_path)); -try_again_CIFSSMBUnixQPathInfo: /* could have done a find first instead but this returns more info */ - rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData, + rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); -/* dump_mem("\nUnixQPathInfo return data", &findData, - sizeof(findData)); */ if (rc) { if (rc == -EREMOTE && !is_dfs_referral) { is_dfs_referral = true; - goto try_again_CIFSSMBUnixQPathInfo; + cERROR(1, ("DFS ref")); /* BB removeme BB */ + /* for DFS, server does not give us real inode data */ + fill_fake_finddataunix(&find_data, sb); + rc = 0; } - goto cgiiu_exit; - } else { - struct cifsInodeInfo *cifsInfo; - __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes); - __u64 end_of_file = le64_to_cpu(findData.EndOfFile); + } + num_of_bytes = le64_to_cpu(find_data.NumOfBytes); + end_of_file = le64_to_cpu(find_data.EndOfFile); - /* get new inode */ + /* get new inode */ + if (*pinode == NULL) { + *pinode = new_inode(sb); if (*pinode == NULL) { - *pinode = new_inode(sb); - if (*pinode == NULL) { - rc = -ENOMEM; - goto cgiiu_exit; - } - /* Is an i_ino of zero legal? */ - /* Are there sanity checks we can use to ensure that - the server is really filling in that field? */ - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { - (*pinode)->i_ino = - (unsigned long)findData.UniqueId; - } /* note ino incremented to unique num in new_inode */ - if (sb->s_flags & MS_NOATIME) - (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; - - insert_inode_hash(*pinode); + rc = -ENOMEM; + goto cgiiu_exit; } + /* Is an i_ino of zero legal? */ + /* note ino incremented to unique num in new_inode */ + /* Are there sanity checks we can use to ensure that + the server is really filling in that field? */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) + (*pinode)->i_ino = (unsigned long)find_data.UniqueId; - inode = *pinode; - cifsInfo = CIFS_I(inode); + if (sb->s_flags & MS_NOATIME) + (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; - cFYI(1, ("Old time %ld", cifsInfo->time)); - cifsInfo->time = jiffies; - cFYI(1, ("New time %ld", cifsInfo->time)); - /* this is ok to set on every inode revalidate */ - atomic_set(&cifsInfo->inUse, 1); + insert_inode_hash(*pinode); + } - cifs_unix_info_to_inode(inode, &findData, 0); + inode = *pinode; + cifsInfo = CIFS_I(inode); + cFYI(1, ("Old time %ld", cifsInfo->time)); + cifsInfo->time = jiffies; + cFYI(1, ("New time %ld", cifsInfo->time)); + /* this is ok to set on every inode revalidate */ + atomic_set(&cifsInfo->inUse, 1); - if (num_of_bytes < end_of_file) - cFYI(1, ("allocation size less than end of file")); - cFYI(1, ("Size %ld and blocks %llu", - (unsigned long) inode->i_size, - (unsigned long long)inode->i_blocks)); + cifs_unix_info_to_inode(inode, &find_data, 0); - cifs_set_ops(inode, is_dfs_referral); - } + if (num_of_bytes < end_of_file) + cFYI(1, ("allocation size less than end of file")); + cFYI(1, ("Size %ld and blocks %llu", + (unsigned long) inode->i_size, + (unsigned long long)inode->i_blocks)); + + cifs_set_ops(inode, is_dfs_referral); cgiiu_exit: return rc; } -- cgit v1.2.3 From b9a3260f25ab5d2ba5c8b9508e7952848b9d704b Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 20 May 2008 21:52:32 +0000 Subject: [CIFS] Enable DFS support for Windows query path info Final piece for handling DFS in query_path_info, constructing a fake inode for the junction directory which the submount will cover. This handles the non-Unix (Windows etc.) code path. Signed-off-by: Steve French --- fs/cifs/inode.c | 324 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 178 insertions(+), 146 deletions(-) (limited to 'fs') diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 422d4e219fa..1cf43e10194 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -161,6 +161,12 @@ static void cifs_unix_info_to_inode(struct inode *inode, spin_unlock(&inode->i_lock); } + +/* + * Needed to setup inode data for the directory which is the + * junction to the new submount (ie to setup the fake directory + * which represents a DFS referral) + */ static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat, struct super_block *sb) { @@ -370,11 +376,42 @@ static int get_sfu_mode(struct inode *inode, #endif } +/* + * Needed to setup inode data for the directory which is the + * junction to the new submount (ie to setup the fake directory + * which represents a DFS referral) + */ +static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat, + struct super_block *sb) +{ + memset(pfnd_dat, sizeof(FILE_ALL_INFO), 0); + +/* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0); + __le64 pfnd_dat->EndOfFile = cpu_to_le64(0); + __u8 pfnd_dat->DeletePending = 0; + __u8 pfnd_data->Directory = 0; + __le32 pfnd_dat->EASize = 0; + __u64 pfnd_dat->IndexNumber = 0; + __u64 pfnd_dat->IndexNumber1 = 0; */ + pfnd_dat->CreationTime = + cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + pfnd_dat->LastAccessTime = + cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + pfnd_dat->LastWriteTime = + cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + pfnd_dat->ChangeTime = + cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY); + pfnd_dat->NumberOfLinks = cpu_to_le32(2); +} + int cifs_get_inode_info(struct inode **pinode, const unsigned char *full_path, FILE_ALL_INFO *pfindData, struct super_block *sb, int xid, const __u16 *pfid) { int rc = 0; + __u32 attr; + struct cifsInodeInfo *cifsInfo; struct cifsTconInfo *pTcon; struct inode *inode; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); @@ -399,7 +436,6 @@ int cifs_get_inode_info(struct inode **pinode, return -ENOMEM; pfindData = (FILE_ALL_INFO *)buf; -try_again_CIFSSMBQPathInfo: /* could do find first instead but this returns more info */ rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, 0 /* not legacy */, @@ -417,171 +453,167 @@ try_again_CIFSSMBQPathInfo: } } /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ - if (rc) { - if (rc == -EREMOTE && !is_dfs_referral) { - is_dfs_referral = true; - goto try_again_CIFSSMBQPathInfo; - } + if (rc == -EREMOTE) { + is_dfs_referral = true; + fill_fake_finddata(pfindData, sb); + rc = 0; + } else if (rc) goto cgii_exit; - } else { - struct cifsInodeInfo *cifsInfo; - __u32 attr = le32_to_cpu(pfindData->Attributes); - /* get new inode */ + attr = le32_to_cpu(pfindData->Attributes); + + /* get new inode */ + if (*pinode == NULL) { + *pinode = new_inode(sb); if (*pinode == NULL) { - *pinode = new_inode(sb); - if (*pinode == NULL) { - rc = -ENOMEM; - goto cgii_exit; - } - /* Is an i_ino of zero legal? Can we use that to check - if the server supports returning inode numbers? Are - there other sanity checks we can use to ensure that - the server is really filling in that field? */ + rc = -ENOMEM; + goto cgii_exit; + } + /* Is an i_ino of zero legal? Can we use that to check + if the server supports returning inode numbers? Are + there other sanity checks we can use to ensure that + the server is really filling in that field? */ - /* We can not use the IndexNumber field by default from - Windows or Samba (in ALL_INFO buf) but we can request - it explicitly. It may not be unique presumably if - the server has multiple devices mounted under one - share */ + /* We can not use the IndexNumber field by default from + Windows or Samba (in ALL_INFO buf) but we can request + it explicitly. It may not be unique presumably if + the server has multiple devices mounted under one share */ - /* There may be higher info levels that work but are - there Windows server or network appliances for which - IndexNumber field is not guaranteed unique? */ + /* There may be higher info levels that work but are + there Windows server or network appliances for which + IndexNumber field is not guaranteed unique? */ - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { - int rc1 = 0; - __u64 inode_num; + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { + int rc1 = 0; + __u64 inode_num; - rc1 = CIFSGetSrvInodeNumber(xid, pTcon, + rc1 = CIFSGetSrvInodeNumber(xid, pTcon, full_path, &inode_num, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - if (rc1) { - cFYI(1, ("GetSrvInodeNum rc %d", rc1)); - /* BB EOPNOSUPP disable SERVER_INUM? */ - } else /* do we need cast or hash to ino? */ - (*pinode)->i_ino = inode_num; - } /* else ino incremented to unique num in new_inode*/ - if (sb->s_flags & MS_NOATIME) - (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; - insert_inode_hash(*pinode); - } - inode = *pinode; - cifsInfo = CIFS_I(inode); - cifsInfo->cifsAttrs = attr; - cFYI(1, ("Old time %ld", cifsInfo->time)); - cifsInfo->time = jiffies; - 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 so ignore it */ - if (pfindData->LastAccessTime) - inode->i_atime = cifs_NTtimeToUnix - (le64_to_cpu(pfindData->LastAccessTime)); - else /* do not need to use current_fs_time - time not stored */ - inode->i_atime = CURRENT_TIME; - inode->i_mtime = + if (rc1) { + cFYI(1, ("GetSrvInodeNum rc %d", rc1)); + /* BB EOPNOSUPP disable SERVER_INUM? */ + } else /* do we need cast or hash to ino? */ + (*pinode)->i_ino = inode_num; + } /* else ino incremented to unique num in new_inode*/ + if (sb->s_flags & MS_NOATIME) + (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; + insert_inode_hash(*pinode); + } + inode = *pinode; + cifsInfo = CIFS_I(inode); + cifsInfo->cifsAttrs = attr; + cFYI(1, ("Old time %ld", cifsInfo->time)); + cifsInfo->time = jiffies; + 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 so ignore it */ + if (pfindData->LastAccessTime) + inode->i_atime = cifs_NTtimeToUnix + (le64_to_cpu(pfindData->LastAccessTime)); + else /* do not need to use current_fs_time - time not stored */ + inode->i_atime = CURRENT_TIME; + 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)); - if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { - inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; - inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; - } + inode->i_ctime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); + cFYI(DBG2, ("Attributes came in as 0x%x", attr)); + if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { + inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; + inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; + } - /* set default mode. will override for dirs below */ - if (atomic_read(&cifsInfo->inUse) == 0) - /* new inode, can safely set these fields */ - inode->i_mode = cifs_sb->mnt_file_mode; - else /* since we set the inode type below we need to mask off - to avoid strange results if type changes and both - get orred in */ - inode->i_mode &= ~S_IFMT; -/* if (attr & ATTR_REPARSE) */ - /* We no longer handle these as symlinks because we could not - follow them due to the absolute path with drive letter */ - if (attr & ATTR_DIRECTORY) { - /* override default perms since we do not do byte range locking - on dirs */ - inode->i_mode = cifs_sb->mnt_dir_mode; - inode->i_mode |= S_IFDIR; - } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (cifsInfo->cifsAttrs & ATTR_SYSTEM) && - /* No need to le64 convert size of zero */ - (pfindData->EndOfFile == 0)) { - inode->i_mode = cifs_sb->mnt_file_mode; - inode->i_mode |= S_IFIFO; + /* set default mode. will override for dirs below */ + if (atomic_read(&cifsInfo->inUse) == 0) + /* new inode, can safely set these fields */ + inode->i_mode = cifs_sb->mnt_file_mode; + else /* since we set the inode type below we need to mask off + to avoid strange results if type changes and both + get orred in */ + inode->i_mode &= ~S_IFMT; +/* if (attr & ATTR_REPARSE) */ + /* We no longer handle these as symlinks because we could not + follow them due to the absolute path with drive letter */ + if (attr & ATTR_DIRECTORY) { + /* override default perms since we do not do byte range locking + on dirs */ + inode->i_mode = cifs_sb->mnt_dir_mode; + inode->i_mode |= S_IFDIR; + } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && + (cifsInfo->cifsAttrs & ATTR_SYSTEM) && + /* No need to le64 convert size of zero */ + (pfindData->EndOfFile == 0)) { + inode->i_mode = cifs_sb->mnt_file_mode; + inode->i_mode |= S_IFIFO; /* BB Finish for SFU style symlinks and devices */ - } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { - if (decode_sfu_inode(inode, - le64_to_cpu(pfindData->EndOfFile), - full_path, - cifs_sb, xid)) - cFYI(1, ("Unrecognized sfu inode type")); - - cFYI(1, ("sfu mode 0%o", inode->i_mode)); - } else { - inode->i_mode |= S_IFREG; - /* treat the dos attribute of read-only as read-only - mode e.g. 555 */ - if (cifsInfo->cifsAttrs & ATTR_READONLY) - inode->i_mode &= ~(S_IWUGO); - else if ((inode->i_mode & S_IWUGO) == 0) - /* the ATTR_READONLY flag may have been */ - /* changed on server -- set any w bits */ - /* allowed by mnt_file_mode */ - inode->i_mode |= (S_IWUGO & - cifs_sb->mnt_file_mode); - /* BB add code here - - validate if device or weird share or device type? */ - } + } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && + (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { + if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile), + full_path, cifs_sb, xid)) + cFYI(1, ("Unrecognized sfu inode type")); - spin_lock(&inode->i_lock); - if (is_size_safe_to_change(cifsInfo, - le64_to_cpu(pfindData->EndOfFile))) { - /* can not safely shrink the file size here if the - client is writing to it due to potential races */ - i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); - - /* 512 bytes (2**9) is the fake blocksize that must be - used for this calculation */ - inode->i_blocks = (512 - 1 + le64_to_cpu( - pfindData->AllocationSize)) >> 9; - } - spin_unlock(&inode->i_lock); + cFYI(1, ("sfu mode 0%o", inode->i_mode)); + } else { + inode->i_mode |= S_IFREG; + /* treat dos attribute of read-only as read-only mode eg 555 */ + if (cifsInfo->cifsAttrs & ATTR_READONLY) + inode->i_mode &= ~(S_IWUGO); + else if ((inode->i_mode & S_IWUGO) == 0) + /* the ATTR_READONLY flag may have been */ + /* changed on server -- set any w bits */ + /* allowed by mnt_file_mode */ + inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode); + /* BB add code to validate if device or weird share or device type? */ + } + + spin_lock(&inode->i_lock); + if (is_size_safe_to_change(cifsInfo, + le64_to_cpu(pfindData->EndOfFile))) { + /* can not safely shrink the file size here if the + client is writing to it due to potential races */ + i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); + + /* 512 bytes (2**9) is the fake blocksize that must be + used for this calculation */ + inode->i_blocks = (512 - 1 + le64_to_cpu( + pfindData->AllocationSize)) >> 9; + } + spin_unlock(&inode->i_lock); - inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); + inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); - /* BB fill in uid and gid here? with help from winbind? - or retrieve from NTFS stream extended attribute */ + /* BB fill in uid and gid here? with help from winbind? + or retrieve from NTFS stream extended attribute */ #ifdef CONFIG_CIFS_EXPERIMENTAL - /* fill in 0777 bits from ACL */ - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { - cFYI(1, ("Getting mode bits from ACL")); - acl_to_uid_mode(inode, full_path, pfid); - } + /* fill in 0777 bits from ACL */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { + cFYI(1, ("Getting mode bits from ACL")); + acl_to_uid_mode(inode, full_path, pfid); + } #endif - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { - /* fill in remaining high mode bits e.g. SUID, VTX */ - get_sfu_mode(inode, full_path, cifs_sb, xid); - } else if (atomic_read(&cifsInfo->inUse) == 0) { - inode->i_uid = cifs_sb->mnt_uid; - inode->i_gid = cifs_sb->mnt_gid; - /* set so we do not keep refreshing these fields with - bad data after user has changed them in memory */ - atomic_set(&cifsInfo->inUse, 1); - } - - cifs_set_ops(inode, is_dfs_referral); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { + /* fill in remaining high mode bits e.g. SUID, VTX */ + get_sfu_mode(inode, full_path, cifs_sb, xid); + } else if (atomic_read(&cifsInfo->inUse) == 0) { + inode->i_uid = cifs_sb->mnt_uid; + inode->i_gid = cifs_sb->mnt_gid; + /* set so we do not keep refreshing these fields with + bad data after user has changed them in memory */ + atomic_set(&cifsInfo->inUse, 1); } + + cifs_set_ops(inode, is_dfs_referral); + + + + cgii_exit: kfree(buf); return rc; -- cgit v1.2.3 From 5651ced3ab196b5e7dc485c5777f210aa41e2d8d Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 20 May 2008 13:02:01 +0400 Subject: Fix possible access to undefined memory region. Signed-off-by: Igor Mammedov Signed-off-by: Steve French --- fs/cifs/dns_resolve.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index 939e256f849..f730ef35499 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c @@ -134,10 +134,6 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) rkey = request_key(&key_type_dns_resolver, name, ""); if (!IS_ERR(rkey)) { data = rkey->payload.data; - cFYI(1, ("%s: resolved: %s to %s", __func__, - rkey->description, - *ip_addr - )); } else { cERROR(1, ("%s: unable to resolve: %s", __func__, name)); goto out; @@ -150,6 +146,11 @@ skip_upcall: if (*ip_addr) { memcpy(*ip_addr, data, len); (*ip_addr)[len] = '\0'; + if (!IS_ERR(rkey)) + cFYI(1, ("%s: resolved: %s to %s", __func__, + name, + *ip_addr + )); rc = 0; } else { rc = -ENOMEM; -- cgit v1.2.3 From 397d71ddfda5b11b85e396d6ea822011c132b962 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 21 May 2008 03:49:46 +0000 Subject: [CIFS] Remove debug statement Signed-off-by: Steve French --- fs/cifs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 1cf43e10194..00ced97bd53 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -222,7 +222,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, if (rc) { if (rc == -EREMOTE && !is_dfs_referral) { is_dfs_referral = true; - cERROR(1, ("DFS ref")); /* BB removeme BB */ + cFYI(DBG2, ("DFS ref")); /* for DFS, server does not give us real inode data */ fill_fake_finddataunix(&find_data, sb); rc = 0; -- cgit v1.2.3 From 13c48c490208d9e70d8d66d56f96c5054db69af7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 21 May 2008 06:32:11 +0100 Subject: fix hppfs Makefile breakage Fallout from commit 46d7b522ebf486edbd096965d534cc6465e9e309 ("uml: move hppfs_kern.c to hppfs.c") Signed-off-by: Al Viro Acked-by: Jeff Dike Signed-off-by: Linus Torvalds --- fs/hppfs/Makefile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/hppfs/Makefile b/fs/hppfs/Makefile index 8a1f5034436..3a982bd975d 100644 --- a/fs/hppfs/Makefile +++ b/fs/hppfs/Makefile @@ -3,7 +3,4 @@ # Licensed under the GPL # -hppfs-objs := hppfs.o - -obj-y = -obj-$(CONFIG_HPPFS) += $(hppfs-objs) +obj-$(CONFIG_HPPFS) += hppfs.o -- cgit v1.2.3 From 79bc12a0a09c2eb1ccbb01c192045f994567bda2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 21 May 2008 06:32:11 +0100 Subject: ecryptfs fixes memcpy() from userland pointer is a Bad Thing(tm) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/ecryptfs/miscdev.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c index 6560da1a58c..50c994a249a 100644 --- a/fs/ecryptfs/miscdev.c +++ b/fs/ecryptfs/miscdev.c @@ -243,7 +243,6 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count, struct ecryptfs_daemon *daemon; struct ecryptfs_msg_ctx *msg_ctx; size_t packet_length_size; - u32 counter_nbo; char packet_length[3]; size_t i; size_t total_length; @@ -328,20 +327,18 @@ check_list: "pending message\n", __func__, count, total_length); goto out_unlock_msg_ctx; } - i = 0; - buf[i++] = msg_ctx->type; - counter_nbo = cpu_to_be32(msg_ctx->counter); - memcpy(&buf[i], (char *)&counter_nbo, 4); - i += 4; + rc = -EFAULT; + if (put_user(msg_ctx->type, buf)) + goto out_unlock_msg_ctx; + if (put_user(cpu_to_be32(msg_ctx->counter), (__be32 __user *)(buf + 1))) + goto out_unlock_msg_ctx; + i = 5; if (msg_ctx->msg) { - memcpy(&buf[i], packet_length, packet_length_size); + if (copy_to_user(&buf[i], packet_length, packet_length_size)) + goto out_unlock_msg_ctx; i += packet_length_size; - rc = copy_to_user(&buf[i], msg_ctx->msg, msg_ctx->msg_size); - if (rc) { - printk(KERN_ERR "%s: copy_to_user returned error " - "[%d]\n", __func__, rc); + if (copy_to_user(&buf[i], msg_ctx->msg, msg_ctx->msg_size)) goto out_unlock_msg_ctx; - } i += msg_ctx->msg_size; } rc = i; @@ -452,7 +449,8 @@ static ssize_t ecryptfs_miscdev_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - u32 counter_nbo, seq; + __be32 counter_nbo; + u32 seq; size_t packet_size, packet_size_length, i; ssize_t sz = 0; char *data; @@ -485,7 +483,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf, count); goto out_free; } - memcpy((char *)&counter_nbo, &data[i], 4); + memcpy(&counter_nbo, &data[i], 4); seq = be32_to_cpu(counter_nbo); i += 4; rc = ecryptfs_parse_packet_length(&data[i], &packet_size, -- cgit v1.2.3 From 9d8df6aa9b1ca74127b11537d91de492dbea666a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 21 May 2008 06:32:11 +0100 Subject: ocfs2 endianness fixes Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/ocfs2/alloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 41f84c92094..10bfb466e06 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -2788,7 +2788,7 @@ static int ocfs2_merge_rec_right(struct inode *inode, BUG_ON(index >= le16_to_cpu(el->l_next_free_rec)); left_rec = &el->l_recs[index]; - if (index == le16_to_cpu(el->l_next_free_rec - 1) && + if (index == le16_to_cpu(el->l_next_free_rec) - 1 && le16_to_cpu(el->l_next_free_rec) == le16_to_cpu(el->l_count)) { /* we meet with a cross extent block merge. */ ret = ocfs2_get_right_path(inode, left_path, &right_path); @@ -2802,7 +2802,7 @@ static int ocfs2_merge_rec_right(struct inode *inode, BUG_ON(next_free <= 0); right_rec = &right_el->l_recs[0]; if (ocfs2_is_empty_extent(right_rec)) { - BUG_ON(le16_to_cpu(next_free) <= 1); + BUG_ON(next_free <= 1); right_rec = &right_el->l_recs[1]; } -- cgit v1.2.3 From 0d817bc0d6cdd92ff1ab2e98dd5878659a48659c Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 22 May 2008 02:02:03 +0000 Subject: [CIFS] Remove redundant NULL check Noticed by Coverity checker. Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 7b9938445b0..9b8b4cfdf99 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2159,8 +2159,7 @@ copyRetry: cFYI(1, ("Send error in copy = %d with %d files copied", rc, le16_to_cpu(pSMBr->CopyCount))); } - if (pSMB) - cifs_buf_release(pSMB); + cifs_buf_release(pSMB); if (rc == -EAGAIN) goto copyRetry; @@ -2249,8 +2248,7 @@ createSymLinkRetry: if (rc) cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc)); - if (pSMB) - cifs_buf_release(pSMB); + cifs_buf_release(pSMB); if (rc == -EAGAIN) goto createSymLinkRetry; @@ -4095,8 +4093,7 @@ getDFSRetry: target_nodes, nls_codepage); GetDFSRefExit: - if (pSMB) - cifs_buf_release(pSMB); + cifs_buf_release(pSMB); if (rc == -EAGAIN) goto getDFSRetry; @@ -5117,8 +5114,7 @@ setPermsRetry: if (rc) cFYI(1, ("SetPathInfo (perms) returned %d", rc)); - if (pSMB) - cifs_buf_release(pSMB); + cifs_buf_release(pSMB); if (rc == -EAGAIN) goto setPermsRetry; return rc; @@ -5340,8 +5336,7 @@ QAllEAsRetry: } } } - if (pSMB) - cifs_buf_release(pSMB); + cifs_buf_release(pSMB); if (rc == -EAGAIN) goto QAllEAsRetry; @@ -5490,8 +5485,7 @@ QEARetry: } } } - if (pSMB) - cifs_buf_release(pSMB); + cifs_buf_release(pSMB); if (rc == -EAGAIN) goto QEARetry; -- cgit v1.2.3 From e4058245ac0c4d9a517cda688a35aef065cb7f4e Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 2 Apr 2008 17:33:47 +0400 Subject: Adds username in the upcall key for unattended mounts with keytab Signed-off-by: Igor Mammedov Signed-off-by: Steve French --- fs/cifs/cifs_spnego.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'fs') diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 6653e29637a..7013aaff6ae 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c @@ -119,6 +119,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) dp = description + strlen(description); sprintf(dp, ";uid=0x%x", sesInfo->linux_uid); + dp = description + strlen(description); + sprintf(dp, ";user=%s", sesInfo->userName); + cFYI(1, ("key description = %s", description)); spnego_key = request_key(&cifs_spnego_key_type, description, ""); -- cgit v1.2.3 From 0a891adccc867c28b022128bc342a779e476c816 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 22 May 2008 14:20:21 +0000 Subject: [CIFS] Fix reversed memset arguments Signed-off-by: Dave Jones Signed-off-by: Steve French --- fs/cifs/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 00ced97bd53..129dbfe4dca 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -172,7 +172,7 @@ static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat, { struct inode *pinode = NULL; - memset(pfnd_dat, sizeof(FILE_UNIX_BASIC_INFO), 0); + memset(pfnd_dat, 0, sizeof(FILE_UNIX_BASIC_INFO)); /* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0); __le64 pfnd_dat->NumOfBytes = cpu_to_le64(0); @@ -384,7 +384,7 @@ static int get_sfu_mode(struct inode *inode, static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat, struct super_block *sb) { - memset(pfnd_dat, sizeof(FILE_ALL_INFO), 0); + memset(pfnd_dat, 0, sizeof(FILE_ALL_INFO)); /* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0); __le64 pfnd_dat->EndOfFile = cpu_to_le64(0); -- cgit v1.2.3 From 978b7237123d007b9fa983af6e0e2fa8f97f9934 Mon Sep 17 00:00:00 2001 From: David Chinner Date: Mon, 19 May 2008 16:29:46 +1000 Subject: [XFS] Fix fsync() b0rkage. xfs_fsync() fails to wait for data I/O completion before checking if the inode is dirty or clean to decide whether to log the inode or not. This misses inode size updates when the data flushed by the fsync() is extending the file. Hence, like fdatasync(), we need to wait for I/o completion first, then check the inode for cleanliness. Doing so makes the behaviour of xfs_fsync() identical for fsync and fdatasync and we *always* use synchronous semantics if the inode is dirty. Therefore also kill the differences and remove the unused flags from the xfs_fsync function and callers. SGI-PV: 981296 SGI-Modid: xfs-linux-melb:xfs-kern:31033a Signed-off-by: David Chinner Signed-off-by: Christoph Hellwig Signed-off-by: Lachlan McIlroy --- fs/xfs/linux-2.6/xfs_file.c | 17 ++++--- fs/xfs/linux-2.6/xfs_vnode.h | 8 ---- fs/xfs/xfs_vnodeops.c | 112 ++++++++++++++++--------------------------- fs/xfs/xfs_vnodeops.h | 3 +- 4 files changed, 54 insertions(+), 86 deletions(-) (limited to 'fs') diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 65e78c13d4a..5f60363b934 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -184,19 +184,24 @@ xfs_file_release( return -xfs_release(XFS_I(inode)); } +/* + * We ignore the datasync flag here because a datasync is effectively + * identical to an fsync. That is, datasync implies that we need to write + * only the metadata needed to be able to access the data that is written + * if we crash after the call completes. Hence if we are writing beyond + * EOF we have to log the inode size change as well, which makes it a + * full fsync. If we don't write beyond EOF, the inode core will be + * clean in memory and so we don't need to log the inode, just like + * fsync. + */ STATIC int xfs_file_fsync( struct file *filp, struct dentry *dentry, int datasync) { - int flags = FSYNC_WAIT; - - if (datasync) - flags |= FSYNC_DATA; xfs_iflags_clear(XFS_I(dentry->d_inode), XFS_ITRUNCATED); - return -xfs_fsync(XFS_I(dentry->d_inode), flags, - (xfs_off_t)0, (xfs_off_t)-1); + return -xfs_fsync(XFS_I(dentry->d_inode)); } /* diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 9d73cb5c0fc..25eb2a9e8d9 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h @@ -229,14 +229,6 @@ static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) #define ATTR_NOLOCK 0x200 /* Don't grab any conflicting locks */ #define ATTR_NOSIZETOK 0x400 /* Don't get the SIZE token */ -/* - * Flags to vop_fsync/reclaim. - */ -#define FSYNC_NOWAIT 0 /* asynchronous flush */ -#define FSYNC_WAIT 0x1 /* synchronous fsync or forced reclaim */ -#define FSYNC_INVAL 0x2 /* flush and invalidate cached data */ -#define FSYNC_DATA 0x4 /* synchronous fsync of data only */ - /* * Tracking vnode activity. */ diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 70702a60b4b..e475e3717eb 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -856,18 +856,14 @@ xfs_readlink( /* * xfs_fsync * - * This is called to sync the inode and its data out to disk. - * We need to hold the I/O lock while flushing the data, and - * the inode lock while flushing the inode. The inode lock CANNOT - * be held while flushing the data, so acquire after we're done - * with that. + * This is called to sync the inode and its data out to disk. We need to hold + * the I/O lock while flushing the data, and the inode lock while flushing the + * inode. The inode lock CANNOT be held while flushing the data, so acquire + * after we're done with that. */ int xfs_fsync( - xfs_inode_t *ip, - int flag, - xfs_off_t start, - xfs_off_t stop) + xfs_inode_t *ip) { xfs_trans_t *tp; int error; @@ -875,103 +871,79 @@ xfs_fsync( xfs_itrace_entry(ip); - ASSERT(start >= 0 && stop >= -1); - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return XFS_ERROR(EIO); - if (flag & FSYNC_DATA) - filemap_fdatawait(vn_to_inode(XFS_ITOV(ip))->i_mapping); + /* capture size updates in I/O completion before writing the inode. */ + error = filemap_fdatawait(vn_to_inode(XFS_ITOV(ip))->i_mapping); + if (error) + return XFS_ERROR(error); /* - * We always need to make sure that the required inode state - * is safe on disk. The vnode might be clean but because - * of committed transactions that haven't hit the disk yet. - * Likewise, there could be unflushed non-transactional - * changes to the inode core that have to go to disk. + * We always need to make sure that the required inode state is safe on + * disk. The vnode might be clean but we still might need to force the + * log because of committed transactions that haven't hit the disk yet. + * Likewise, there could be unflushed non-transactional changes to the + * inode core that have to go to disk and this requires us to issue + * a synchronous transaction to capture these changes correctly. * - * The following code depends on one assumption: that - * any transaction that changes an inode logs the core - * because it has to change some field in the inode core - * (typically nextents or nblocks). That assumption - * implies that any transactions against an inode will - * catch any non-transactional updates. If inode-altering - * transactions exist that violate this assumption, the - * code breaks. Right now, it figures that if the involved - * update_* field is clear and the inode is unpinned, the - * inode is clean. Either it's been flushed or it's been - * committed and the commit has hit the disk unpinning the inode. - * (Note that xfs_inode_item_format() called at commit clears - * the update_* fields.) + * This code relies on the assumption that if the update_* fields + * of the inode are clear and the inode is unpinned then it is clean + * and no action is required. */ xfs_ilock(ip, XFS_ILOCK_SHARED); - /* If we are flushing data then we care about update_size - * being set, otherwise we care about update_core - */ - if ((flag & FSYNC_DATA) ? - (ip->i_update_size == 0) : - (ip->i_update_core == 0)) { + if (!(ip->i_update_size || ip->i_update_core)) { /* - * Timestamps/size haven't changed since last inode - * flush or inode transaction commit. That means - * either nothing got written or a transaction - * committed which caught the updates. If the - * latter happened and the transaction hasn't - * hit the disk yet, the inode will be still - * be pinned. If it is, force the log. + * Timestamps/size haven't changed since last inode flush or + * inode transaction commit. That means either nothing got + * written or a transaction committed which caught the updates. + * If the latter happened and the transaction hasn't hit the + * disk yet, the inode will be still be pinned. If it is, + * force the log. */ xfs_iunlock(ip, XFS_ILOCK_SHARED); if (xfs_ipincount(ip)) { - _xfs_log_force(ip->i_mount, (xfs_lsn_t)0, - XFS_LOG_FORCE | - ((flag & FSYNC_WAIT) - ? XFS_LOG_SYNC : 0), + error = _xfs_log_force(ip->i_mount, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC, &log_flushed); } else { /* - * If the inode is not pinned and nothing - * has changed we don't need to flush the - * cache. + * If the inode is not pinned and nothing has changed + * we don't need to flush the cache. */ changed = 0; } - error = 0; } else { /* - * Kick off a transaction to log the inode - * core to get the updates. Make it - * sync if FSYNC_WAIT is passed in (which - * is done by everybody but specfs). The - * sync transaction will also force the log. + * Kick off a transaction to log the inode core to get the + * updates. The sync transaction will also force the log. */ xfs_iunlock(ip, XFS_ILOCK_SHARED); tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS); - if ((error = xfs_trans_reserve(tp, 0, - XFS_FSYNC_TS_LOG_RES(ip->i_mount), - 0, 0, 0))) { + error = xfs_trans_reserve(tp, 0, + XFS_FSYNC_TS_LOG_RES(ip->i_mount), 0, 0, 0); + if (error) { xfs_trans_cancel(tp, 0); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); /* - * Note - it's possible that we might have pushed - * ourselves out of the way during trans_reserve - * which would flush the inode. But there's no - * guarantee that the inode buffer has actually - * gone out yet (it's delwri). Plus the buffer - * could be pinned anyway if it's part of an - * inode in another recent transaction. So we - * play it safe and fire off the transaction anyway. + * Note - it's possible that we might have pushed ourselves out + * of the way during trans_reserve which would flush the inode. + * But there's no guarantee that the inode buffer has actually + * gone out yet (it's delwri). Plus the buffer could be pinned + * anyway if it's part of an inode in another recent + * transaction. So we play it safe and fire off the + * transaction anyway. */ xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - if (flag & FSYNC_WAIT) - xfs_trans_set_sync(tp); + xfs_trans_set_sync(tp); error = _xfs_trans_commit(tp, 0, &log_flushed); xfs_iunlock(ip, XFS_ILOCK_EXCL); diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index 8abe8f186e2..57335ba4ce5 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h @@ -18,8 +18,7 @@ int xfs_open(struct xfs_inode *ip); int xfs_setattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags, struct cred *credp); int xfs_readlink(struct xfs_inode *ip, char *link); -int xfs_fsync(struct xfs_inode *ip, int flag, xfs_off_t start, - xfs_off_t stop); +int xfs_fsync(struct xfs_inode *ip); int xfs_release(struct xfs_inode *ip); int xfs_inactive(struct xfs_inode *ip); int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, -- cgit v1.2.3 From 49383b0e98ad1f69ff4c816eb1961f703df12318 Mon Sep 17 00:00:00 2001 From: David Chinner Date: Mon, 19 May 2008 16:29:34 +1000 Subject: [XFS] Don't allow memory reclaim to wait on the filesystem in inode writeback If we allow memory reclaim to wait on the pages under writeback in inode cluster writeback we could deadlock because we are currently holding the ILOCK on the initial writeback inode which is needed in data I/O completion to change the file size or do unwritten extent conversion before the pages are taken out of writeback state. SGI-PV: 981091 SGI-Modid: xfs-linux-melb:xfs-kern:31015a Signed-off-by: David Chinner Signed-off-by: Christoph Hellwig Signed-off-by: Lachlan McIlroy --- fs/xfs/xfs_inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index cf0bb9c1d62..739ea45a9d1 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2986,7 +2986,7 @@ xfs_iflush_cluster( ASSERT(pag->pag_ici_init); ilist_size = XFS_INODE_CLUSTER_SIZE(mp) * sizeof(xfs_inode_t *); - ilist = kmem_alloc(ilist_size, KM_MAYFAIL); + ilist = kmem_alloc(ilist_size, KM_MAYFAIL|KM_NOFS); if (!ilist) return 0; -- cgit v1.2.3 From c8f5f12e46f079a954d4f7163ba59dadee08ca26 Mon Sep 17 00:00:00 2001 From: David Chinner Date: Tue, 20 May 2008 11:30:15 +1000 Subject: [XFS] Fix inode list allocation size in writeback. We only need to allocate space for the number of inodes in the cluster when writing back inodes, not every byte in the inode cluster. This reduces the amount of memory needing to be allocated to 256 bytes instead of 64k. SGI-PV: 981949 SGI-Modid: xfs-linux-melb:xfs-kern:31182a Signed-off-by: David Chinner Signed-off-by: Christoph Hellwig Signed-off-by: Lachlan McIlroy --- fs/xfs/xfs_inode.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 739ea45a9d1..e569bf5d6cf 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2974,6 +2974,7 @@ xfs_iflush_cluster( xfs_mount_t *mp = ip->i_mount; xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino); unsigned long first_index, mask; + unsigned long inodes_per_cluster; int ilist_size; xfs_inode_t **ilist; xfs_inode_t *iq; @@ -2985,7 +2986,8 @@ xfs_iflush_cluster( ASSERT(pag->pagi_inodeok); ASSERT(pag->pag_ici_init); - ilist_size = XFS_INODE_CLUSTER_SIZE(mp) * sizeof(xfs_inode_t *); + inodes_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog; + ilist_size = inodes_per_cluster * sizeof(xfs_inode_t *); ilist = kmem_alloc(ilist_size, KM_MAYFAIL|KM_NOFS); if (!ilist) return 0; @@ -2995,8 +2997,7 @@ xfs_iflush_cluster( read_lock(&pag->pag_ici_lock); /* really need a gang lookup range call here */ nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, (void**)ilist, - first_index, - XFS_INODE_CLUSTER_SIZE(mp)); + first_index, inodes_per_cluster); if (nr_found == 0) goto out_free; -- cgit v1.2.3 From 6ab455eeaff6893cd06da33843e840d888cdc04a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 19 May 2008 16:34:42 +1000 Subject: [XFS] Fix memory corruption with small buffer reads When we have multiple buffers in a single page for a blocksize == pagesize filesystem we might overwrite the page contents if two callers hit it shortly after each other. To prevent that we need to keep the page locked until I/O is completed and the page marked uptodate. Thanks to Eric Sandeen for triaging this bug and finding a reproducible testcase and Dave Chinner for additional advice. This should fix kernel.org bz #10421. Tested-by: Eric Sandeen SGI-PV: 981813 SGI-Modid: xfs-linux-melb:xfs-kern:31173a Signed-off-by: Christoph Hellwig Signed-off-by: David Chinner Signed-off-by: Lachlan McIlroy --- fs/xfs/linux-2.6/xfs_buf.c | 24 ++++++++++++++++++++---- fs/xfs/linux-2.6/xfs_buf.h | 19 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 5105015a75a..98e0e86093b 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -387,6 +387,8 @@ _xfs_buf_lookup_pages( if (unlikely(page == NULL)) { if (flags & XBF_READ_AHEAD) { bp->b_page_count = i; + for (i = 0; i < bp->b_page_count; i++) + unlock_page(bp->b_pages[i]); return -ENOMEM; } @@ -416,17 +418,24 @@ _xfs_buf_lookup_pages( ASSERT(!PagePrivate(page)); if (!PageUptodate(page)) { page_count--; - if (blocksize < PAGE_CACHE_SIZE && !PagePrivate(page)) { + if (blocksize >= PAGE_CACHE_SIZE) { + if (flags & XBF_READ) + bp->b_flags |= _XBF_PAGE_LOCKED; + } else if (!PagePrivate(page)) { if (test_page_region(page, offset, nbytes)) page_count++; } } - unlock_page(page); bp->b_pages[i] = page; offset = 0; } + if (!(bp->b_flags & _XBF_PAGE_LOCKED)) { + for (i = 0; i < bp->b_page_count; i++) + unlock_page(bp->b_pages[i]); + } + if (page_count == bp->b_page_count) bp->b_flags |= XBF_DONE; @@ -746,6 +755,7 @@ xfs_buf_associate_memory( bp->b_count_desired = len; bp->b_buffer_length = buflen; bp->b_flags |= XBF_MAPPED; + bp->b_flags &= ~_XBF_PAGE_LOCKED; return 0; } @@ -1093,8 +1103,10 @@ _xfs_buf_ioend( xfs_buf_t *bp, int schedule) { - if (atomic_dec_and_test(&bp->b_io_remaining) == 1) + if (atomic_dec_and_test(&bp->b_io_remaining) == 1) { + bp->b_flags &= ~_XBF_PAGE_LOCKED; xfs_buf_ioend(bp, schedule); + } } STATIC void @@ -1125,6 +1137,9 @@ xfs_buf_bio_end_io( if (--bvec >= bio->bi_io_vec) prefetchw(&bvec->bv_page->flags); + + if (bp->b_flags & _XBF_PAGE_LOCKED) + unlock_page(page); } while (bvec >= bio->bi_io_vec); _xfs_buf_ioend(bp, 1); @@ -1163,7 +1178,8 @@ _xfs_buf_ioapply( * filesystem block size is not smaller than the page size. */ if ((bp->b_buffer_length < PAGE_CACHE_SIZE) && - (bp->b_flags & XBF_READ) && + ((bp->b_flags & (XBF_READ|_XBF_PAGE_LOCKED)) == + (XBF_READ|_XBF_PAGE_LOCKED)) && (blocksize >= PAGE_CACHE_SIZE)) { bio = bio_alloc(GFP_NOIO, 1); diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index 841d7883528..f948ec7ba9a 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -66,6 +66,25 @@ typedef enum { _XBF_PAGES = (1 << 18), /* backed by refcounted pages */ _XBF_RUN_QUEUES = (1 << 19),/* run block device task queue */ _XBF_DELWRI_Q = (1 << 21), /* buffer on delwri queue */ + + /* + * Special flag for supporting metadata blocks smaller than a FSB. + * + * In this case we can have multiple xfs_buf_t on a single page and + * need to lock out concurrent xfs_buf_t readers as they only + * serialise access to the buffer. + * + * If the FSB size >= PAGE_CACHE_SIZE case, we have no serialisation + * between reads of the page. Hence we can have one thread read the + * page and modify it, but then race with another thread that thinks + * the page is not up-to-date and hence reads it again. + * + * The result is that the first modifcation to the page is lost. + * This sort of AGF/AGI reading race can happen when unlinking inodes + * that require truncation and results in the AGI unlinked list + * modifications being lost. + */ + _XBF_PAGE_LOCKED = (1 << 22), } xfs_buf_flags_t; typedef enum { -- cgit v1.2.3 From aaa9bbe039febf1d3a0f3a374deea0680d9f5758 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 May 2008 17:38:32 +0000 Subject: [CIFS] remove unused variables CC: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 3 +-- fs/cifs/cifssmb.c | 6 ++---- fs/cifs/file.c | 7 ------- fs/cifs/misc.c | 3 +-- fs/cifs/readdir.c | 6 +----- 5 files changed, 5 insertions(+), 20 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 08914053242..9cfcf326ead 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -333,7 +333,6 @@ struct cifsFileInfo { bool messageMode:1; /* for pipes: message vs byte mode */ atomic_t wrtPending; /* handle in use - defer close */ struct semaphore fh_sem; /* prevents reopen race after dead ses*/ - char *search_resume_name; /* BB removeme BB */ struct cifs_search_info srch_inf; }; @@ -626,7 +625,7 @@ GLOBAL_EXTERN atomic_t tcpSesAllocCount; GLOBAL_EXTERN atomic_t tcpSesReconnectCount; GLOBAL_EXTERN atomic_t tconInfoReconnectCount; -/* Various Debug counters to remove someday (BB) */ +/* Various Debug counters */ GLOBAL_EXTERN atomic_t bufAllocCount; /* current number allocated */ #ifdef CONFIG_CIFS_STATS2 GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 9b8b4cfdf99..174bf8aca23 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1728,7 +1728,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, { int rc = 0; LOCK_REQ *pSMB = NULL; - LOCK_RSP *pSMBr = NULL; +/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */ int bytes_returned; int timeout = 0; __u16 count; @@ -1739,8 +1739,6 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, if (rc) return rc; - pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */ - if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) { timeout = CIFS_ASYNC_OP; /* no response expected */ pSMB->Timeout = 0; @@ -1774,7 +1772,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, if (waitFlag) { rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned); + (struct smb_hdr *) pSMB, &bytes_returned); cifs_small_buf_release(pSMB); } else { rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8636cec2642..0aac824371a 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -546,7 +546,6 @@ int cifs_close(struct inode *inode, struct file *file) msleep(timeout); timeout *= 8; } - kfree(pSMBFile->search_resume_name); kfree(file->private_data); file->private_data = NULL; } else @@ -605,12 +604,6 @@ int cifs_closedir(struct inode *inode, struct file *file) else cifs_buf_release(ptmp); } - ptmp = pCFileStruct->search_resume_name; - if (ptmp) { - cFYI(1, ("closedir free resume name")); - pCFileStruct->search_resume_name = NULL; - kfree(ptmp); - } kfree(file->private_data); file->private_data = NULL; } diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1d69b8014e0..4b17f8fe315 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -519,8 +519,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) 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 */ + pnotify->FileName, pnotify->Action)); /* cifs_dump_mem("Rcvd notify Data: ",buf, sizeof(struct smb_hdr)+60); */ return true; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 713c2511019..df2c3c466ee 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -675,8 +675,6 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, cifsFile->invalidHandle = true; CIFSFindClose(xid, pTcon, cifsFile->netfid); } - kfree(cifsFile->search_resume_name); - cifsFile->search_resume_name = NULL; if (cifsFile->srch_inf.ntwrk_buf_start) { cFYI(1, ("freeing SMB ff cache buf on search rewind")); if (cifsFile->srch_inf.smallBuf) @@ -1043,9 +1041,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) } /* else { cifsFile->invalidHandle = true; CIFSFindClose(xid, pTcon, cifsFile->netfid); - } - kfree(cifsFile->search_resume_name); - cifsFile->search_resume_name = NULL; */ + } */ rc = find_cifs_entry(xid, pTcon, file, ¤t_entry, &num_to_fill); -- cgit v1.2.3 From 4468eb3fd102cad559e51594a01cbc65b994d264 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 22 May 2008 09:31:40 -0400 Subject: on non-posix shares, clear write bits in mode when ATTR_READONLY is set When mounting a share with posix extensions disabled, cifs_get_inode_info turns off all the write bits in the mode for regular files if ATTR_READONLY is set. Directories and other inode types, however, can also have ATTR_READONLY set, but the mode gives no indication of this. This patch makes this apply to other inode types besides regular files. It also cleans up how modes are set in cifs_get_inode_info for both the "normal" and "dynperm" cases. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/inode.c | 76 ++++++++++++++++++++++++++----------------------------- fs/cifs/readdir.c | 71 ++++++++++++++++++++++++++++----------------------- 2 files changed, 75 insertions(+), 72 deletions(-) (limited to 'fs') diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 129dbfe4dca..ae5bcaf2031 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -418,6 +418,7 @@ int cifs_get_inode_info(struct inode **pinode, char *buf = NULL; bool adjustTZ = false; bool is_dfs_referral = false; + umode_t default_mode; pTcon = cifs_sb->tcon; cFYI(1, ("Getting info on %s", full_path)); @@ -530,47 +531,42 @@ int cifs_get_inode_info(struct inode **pinode, inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; } - /* set default mode. will override for dirs below */ - if (atomic_read(&cifsInfo->inUse) == 0) - /* new inode, can safely set these fields */ - inode->i_mode = cifs_sb->mnt_file_mode; - else /* since we set the inode type below we need to mask off - to avoid strange results if type changes and both - get orred in */ - inode->i_mode &= ~S_IFMT; -/* if (attr & ATTR_REPARSE) */ - /* We no longer handle these as symlinks because we could not - follow them due to the absolute path with drive letter */ - if (attr & ATTR_DIRECTORY) { - /* override default perms since we do not do byte range locking - on dirs */ - inode->i_mode = cifs_sb->mnt_dir_mode; - inode->i_mode |= S_IFDIR; - } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (cifsInfo->cifsAttrs & ATTR_SYSTEM) && - /* No need to le64 convert size of zero */ - (pfindData->EndOfFile == 0)) { - inode->i_mode = cifs_sb->mnt_file_mode; - inode->i_mode |= S_IFIFO; -/* BB Finish for SFU style symlinks and devices */ - } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { - if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile), - full_path, cifs_sb, xid)) - cFYI(1, ("Unrecognized sfu inode type")); - - cFYI(1, ("sfu mode 0%o", inode->i_mode)); + /* get default inode mode */ + if (attr & ATTR_DIRECTORY) + default_mode = cifs_sb->mnt_dir_mode; + else + default_mode = cifs_sb->mnt_file_mode; + + /* set permission bits */ + if (atomic_read(&cifsInfo->inUse) == 0 || + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) + inode->i_mode = default_mode; + else { + /* just reenable write bits if !ATTR_READONLY */ + if ((inode->i_mode & S_IWUGO) == 0 && + (attr & ATTR_READONLY) == 0) + inode->i_mode |= (S_IWUGO & default_mode); + inode->i_mode &= ~S_IFMT; + } + /* clear write bits if ATTR_READONLY is set */ + if (attr & ATTR_READONLY) + inode->i_mode &= ~S_IWUGO; + + /* set inode type */ + if ((attr & ATTR_SYSTEM) && + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { + /* no need to fix endianness on 0 */ + if (pfindData->EndOfFile == 0) + inode->i_mode |= S_IFIFO; + else if (decode_sfu_inode(inode, + le64_to_cpu(pfindData->EndOfFile), + full_path, cifs_sb, xid)) + cFYI(1, ("unknown SFU file type\n")); } else { - inode->i_mode |= S_IFREG; - /* treat dos attribute of read-only as read-only mode eg 555 */ - if (cifsInfo->cifsAttrs & ATTR_READONLY) - inode->i_mode &= ~(S_IWUGO); - else if ((inode->i_mode & S_IWUGO) == 0) - /* the ATTR_READONLY flag may have been */ - /* changed on server -- set any w bits */ - /* allowed by mnt_file_mode */ - inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode); - /* BB add code to validate if device or weird share or device type? */ + if (attr & ATTR_DIRECTORY) + inode->i_mode |= S_IFDIR; + else + inode->i_mode |= S_IFREG; } spin_lock(&inode->i_lock); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index df2c3c466ee..83f30695488 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -132,6 +132,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, __u32 attr; __u64 allocation_size; __u64 end_of_file; + umode_t default_mode; /* save mtime and size */ local_mtime = tmp_inode->i_mtime; @@ -187,48 +188,54 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, if (atomic_read(&cifsInfo->inUse) == 0) { tmp_inode->i_uid = cifs_sb->mnt_uid; tmp_inode->i_gid = cifs_sb->mnt_gid; - /* set default mode. will override for dirs below */ - tmp_inode->i_mode = cifs_sb->mnt_file_mode; - } else { - /* mask off the type bits since it gets set - below and we do not want to get two type - bits set */ + } + + if (attr & ATTR_DIRECTORY) + default_mode = cifs_sb->mnt_dir_mode; + else + default_mode = cifs_sb->mnt_file_mode; + + /* set initial permissions */ + if ((atomic_read(&cifsInfo->inUse) == 0) || + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) + tmp_inode->i_mode = default_mode; + else { + /* just reenable write bits if !ATTR_READONLY */ + if ((tmp_inode->i_mode & S_IWUGO) == 0 && + (attr & ATTR_READONLY) == 0) + tmp_inode->i_mode |= (S_IWUGO & default_mode); + tmp_inode->i_mode &= ~S_IFMT; } - if (attr & ATTR_DIRECTORY) { - *pobject_type = DT_DIR; - /* override default perms since we do not lock dirs */ - if (atomic_read(&cifsInfo->inUse) == 0) - tmp_inode->i_mode = cifs_sb->mnt_dir_mode; - tmp_inode->i_mode |= S_IFDIR; - } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (attr & ATTR_SYSTEM)) { + /* clear write bits if ATTR_READONLY is set */ + if (attr & ATTR_READONLY) + tmp_inode->i_mode &= ~S_IWUGO; + + /* set inode type */ + if ((attr & ATTR_SYSTEM) && + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { if (end_of_file == 0) { - *pobject_type = DT_FIFO; tmp_inode->i_mode |= S_IFIFO; + *pobject_type = DT_FIFO; } else { - /* rather than get the type here, we mark the - inode as needing revalidate and get the real type - (blk vs chr vs. symlink) later ie in lookup */ - *pobject_type = DT_REG; + /* + * trying to get the type can be slow, so just call + * this a regular file for now, and mark for reval + */ tmp_inode->i_mode |= S_IFREG; + *pobject_type = DT_REG; cifsInfo->time = 0; } -/* we no longer mark these because we could not follow them */ -/* } else if (attr & ATTR_REPARSE) { - *pobject_type = DT_LNK; - tmp_inode->i_mode |= S_IFLNK; */ } else { - *pobject_type = DT_REG; - tmp_inode->i_mode |= S_IFREG; - if (attr & ATTR_READONLY) - tmp_inode->i_mode &= ~(S_IWUGO); - else if ((tmp_inode->i_mode & S_IWUGO) == 0) - /* the ATTR_READONLY flag may have been changed on */ - /* server -- set any w bits allowed by mnt_file_mode */ - tmp_inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode); - } /* could add code here - to validate if device or weird share type? */ + if (attr & ATTR_DIRECTORY) { + tmp_inode->i_mode |= S_IFDIR; + *pobject_type = DT_DIR; + } else { + tmp_inode->i_mode |= S_IFREG; + *pobject_type = DT_REG; + } + } /* can not fill in nlink here as in qpathinfo version and Unx search */ if (atomic_read(&cifsInfo->inUse) == 0) -- cgit v1.2.3 From b0fd30d3e7e768aad5e398caaea6ae5a5c814eab Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 22 May 2008 09:33:34 -0400 Subject: when creating new inodes, use file_mode/dir_mode exclusively on mount without unix extensions When CIFS creates a new inode on a mount without unix extensions, it temporarily assigns the mode that was passed to it in the create/mkdir call. Eventually, when the inode is revalidated, it changes to have the file_mode or dir_mode for the mount. This is confusing to users who expect that the mode shouldn't change this way. It's also problematic since only the mode is treated this way, not the uid or gid. Suppose you have a CIFS mount that's mounted with: uid=0,gid=0,file_mode=0666,dir_mode=0777 ...if an unprivileged user comes along and does this on the mount: mkdir -m 0700 foo touch foo/bar ...there is a period of time where the touch will fail, since the dir will initially be owned by root and have mode 0700. If the user waits long enough, then "foo" will be revalidated and will get the correct dir_mode permissions. This patch changes cifs_mkdir and cifs_create to not overwrite the mode found by the initial cifs_get_inode_info call after the inode is created on the server. Legacy behavior can be reenabled with the new "dynperm" mount option. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/dir.c | 4 +++- fs/cifs/inode.c | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f0b5b5f3dd2..fb69c1fa85c 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -260,7 +260,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, buf, inode->i_sb, xid, &fileHandle); if (newinode) { - newinode->i_mode = mode; + if (cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_DYNPERM) + newinode->i_mode = mode; if ((oplock & CIFS_CREATE_ACTION) && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ae5bcaf2031..12667d6bf30 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1015,8 +1015,11 @@ mkdir_get_info: CIFS_MOUNT_MAP_SPECIAL_CHR); } if (direntry->d_inode) { - direntry->d_inode->i_mode = mode; - direntry->d_inode->i_mode |= S_IFDIR; + if (cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_DYNPERM) + direntry->d_inode->i_mode = + (mode | S_IFDIR); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { direntry->d_inode->i_uid = -- cgit v1.2.3 From 4e94a105ed0df78e25b20ff8ed6761f5937662b1 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 May 2008 18:22:46 +0000 Subject: [CIFS] remove trailing whitespace Signed-off-by: Steve French --- fs/cifs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 12667d6bf30..ae6b725b366 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1019,7 +1019,7 @@ mkdir_get_info: CIFS_MOUNT_DYNPERM) direntry->d_inode->i_mode = (mode | S_IFDIR); - + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { direntry->d_inode->i_uid = -- cgit v1.2.3 From 4ca691a892e8ab4f79583de1394f17a7dcfa2b57 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 22 May 2008 09:33:34 -0400 Subject: silently ignore ownership changes unless unix extensions are enabled or we're faking uid changes CIFS currently allows you to change the ownership of a file, but unless unix extensions are enabled this change is not passed off to the server. Have CIFS silently ignore ownership changes that can't be persistently stored on the server unless the "setuids" option is explicitly specified. We could return an error here (-EOPNOTSUPP or something), but this is how most disk-based windows filesystems on behave on Linux (e.g. VFAT, NTFS, etc). With cifsacl support and proper Windows to Unix idmapping support, we may be able to do this more properly in the future. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/inode.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ae6b725b366..fe752fdb26c 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1546,13 +1546,26 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) } else goto cifs_setattr_exit; } - if (attrs->ia_valid & ATTR_UID) { - cFYI(1, ("UID changed to %d", attrs->ia_uid)); - uid = attrs->ia_uid; - } - if (attrs->ia_valid & ATTR_GID) { - cFYI(1, ("GID changed to %d", attrs->ia_gid)); - gid = attrs->ia_gid; + + /* + * Without unix extensions we can't send ownership changes to the + * server, so silently ignore them. This is consistent with how + * local DOS/Windows filesystems behave (VFAT, NTFS, etc). With + * CIFSACL support + proper Windows to Unix idmapping, we may be + * able to support this in the future. + */ + if (!pTcon->unix_ext && + !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { + attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); + } else { + if (attrs->ia_valid & ATTR_UID) { + cFYI(1, ("UID changed to %d", attrs->ia_uid)); + uid = attrs->ia_uid; + } + if (attrs->ia_valid & ATTR_GID) { + cFYI(1, ("GID changed to %d", attrs->ia_gid)); + gid = attrs->ia_gid; + } } time_buf.Attributes = 0; -- cgit v1.2.3 From 27adb44c4f671d15932eb0702a09d27244a8a7c1 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 May 2008 19:43:29 +0000 Subject: [CIFS] warn if both dynperm and cifsacl mount options specified Signed-off-by: Steve French --- fs/cifs/connect.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 023434f72c1..d49e274f8eb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2120,6 +2120,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; } + if ((volume_info.cifs_acl) && (volume_info.dynperm)) + cERROR(1, ("mount option dynperm ignored if cifsacl " + "mount option supported")); + tcon = find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, volume_info.username); -- cgit v1.2.3 From b7206153f61bb63ee2cffa63905b57ec01d20e6e Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 May 2008 20:35:07 +0000 Subject: [CIFS] Correct incorrect obscure open flag Also add defines for pipe subcommand codes Signed-off-by: Steve French --- fs/cifs/cifspdu.h | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 65d58b4e6a6..0f327c224da 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -79,6 +79,19 @@ #define TRANS2_GET_DFS_REFERRAL 0x10 #define TRANS2_REPORT_DFS_INCOSISTENCY 0x11 +/* SMB Transact (Named Pipe) subcommand codes */ +#define TRANS_SET_NMPIPE_STATE 0x0001 +#define TRANS_RAW_READ_NMPIPE 0x0011 +#define TRANS_QUERY_NMPIPE_STATE 0x0021 +#define TRANS_QUERY_NMPIPE_INFO 0x0022 +#define TRANS_PEEK_NMPIPE 0x0023 +#define TRANS_TRANSACT_NMPIPE 0x0026 +#define TRANS_RAW_WRITE_NMPIPE 0x0031 +#define TRANS_READ_NMPIPE 0x0036 +#define TRANS_WRITE_NMPIPE 0x0037 +#define TRANS_WAIT_NMPIPE 0x0053 +#define TRANS_CALL_NMPIPE 0x0054 + /* NT Transact subcommand codes */ #define NT_TRANSACT_CREATE 0x01 #define NT_TRANSACT_IOCTL 0x02 @@ -328,12 +341,13 @@ #define CREATE_COMPLETE_IF_OPLK 0x00000100 /* should be zero */ #define CREATE_NO_EA_KNOWLEDGE 0x00000200 #define CREATE_EIGHT_DOT_THREE 0x00000400 /* doc says this is obsolete - open for recovery flag - should - be zero */ + "open for recovery" flag - should + be zero in any case */ +#define CREATE_OPEN_FOR_RECOVERY 0x00000400 #define CREATE_RANDOM_ACCESS 0x00000800 #define CREATE_DELETE_ON_CLOSE 0x00001000 #define CREATE_OPEN_BY_ID 0x00002000 -#define CREATE_OPEN_BACKUP_INTN 0x00004000 +#define CREATE_OPEN_BACKUP_INTENT 0x00004000 #define CREATE_NO_COMPRESSION 0x00008000 #define CREATE_RESERVE_OPFILTER 0x00100000 /* should be zero */ #define OPEN_REPARSE_POINT 0x00200000 @@ -722,7 +736,6 @@ typedef struct smb_com_tconx_rsp_ext { #define SMB_CSC_CACHE_AUTO_REINT 0x0004 #define SMB_CSC_CACHE_VDO 0x0008 #define SMB_CSC_NO_CACHING 0x000C - #define SMB_UNIQUE_FILE_NAME 0x0010 #define SMB_EXTENDED_SIGNATURES 0x0020 @@ -806,7 +819,7 @@ typedef struct smb_com_findclose_req { #define ICOUNT_MASK 0x00FF #define PIPE_READ_MODE 0x0100 #define NAMED_PIPE_TYPE 0x0400 -#define PIPE_END_POINT 0x0800 +#define PIPE_END_POINT 0x4000 #define BLOCKING_NAMED_PIPE 0x8000 typedef struct smb_com_open_req { /* also handles create */ -- cgit v1.2.3 From 03fb0bce01490c9bdedad861962c76f987531014 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 23 May 2008 13:04:19 -0700 Subject: fuse: fix bdi naming conflict Fuse allocates a separate bdi for each filesystem, and registers them in sysfs with "MAJOR:MINOR" of sb->s_dev (st_dev). This works fine for anon devices normally used by fuse, but can conflict with an already registered BDI for "fuseblk" filesystems, where sb->s_dev represents a real block device. In particularl this happens if a non-partitioned device is being mounted. Fix by registering with a different name for "fuseblk" filesystems. Thanks to Ioan Ionita for the bug report. Signed-off-by: Miklos Szeredi Reported-by: Ioan Ionita Tested-by: Ioan Ionita Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fuse/inode.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index fb77e096213..43e99513334 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -488,7 +488,12 @@ static struct fuse_conn *new_conn(struct super_block *sb) err = bdi_init(&fc->bdi); if (err) goto error_kfree; - err = bdi_register_dev(&fc->bdi, fc->dev); + if (sb->s_bdev) { + err = bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk", + MAJOR(fc->dev), MINOR(fc->dev)); + } else { + err = bdi_register_dev(&fc->bdi, fc->dev); + } if (err) goto error_bdi_destroy; /* -- cgit v1.2.3 From 71fd5179e8d1d4d503b517e0c5374f7c49540bfc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 23 May 2008 13:04:20 -0700 Subject: ecryptfs: fix missed mutex_unlock Cc: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ecryptfs/crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index cd62d75b2cc..e2832bc7869 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1906,9 +1906,9 @@ int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, goto out; } } - mutex_unlock(&key_tfm_list_mutex); (*tfm) = key_tfm->key_tfm; (*tfm_mutex) = &key_tfm->key_tfm_mutex; out: + mutex_unlock(&key_tfm_list_mutex); return rc; } -- cgit v1.2.3 From 80bfc25f42db6d4715c7688ae2352c5a8038fe7e Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Fri, 23 May 2008 13:04:22 -0700 Subject: ntfs: le*_add_cpu conversion replace all: little_endian_variable = cpu_to_leX(leX_to_cpu(little_endian_variable) + expression_in_cpu_byteorder); with: leX_add_cpu(&little_endian_variable, expression_in_cpu_byteorder); generated with semantic patch Signed-off-by: Marcin Slusarz Acked-by: Anton Altaparmakov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ntfs/upcase.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/ntfs/upcase.c b/fs/ntfs/upcase.c index 9101807dc81..e2f72ca9803 100644 --- a/fs/ntfs/upcase.c +++ b/fs/ntfs/upcase.c @@ -77,11 +77,10 @@ ntfschar *generate_default_upcase(void) uc[i] = cpu_to_le16(i); for (r = 0; uc_run_table[r][0]; r++) for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++) - uc[i] = cpu_to_le16(le16_to_cpu(uc[i]) + - uc_run_table[r][2]); + le16_add_cpu(&uc[i], uc_run_table[r][2]); for (r = 0; uc_dup_table[r][0]; r++) for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2) - uc[i + 1] = cpu_to_le16(le16_to_cpu(uc[i + 1]) - 1); + le16_add_cpu(&uc[i + 1], -1); for (r = 0; uc_word_table[r][0]; r++) uc[uc_word_table[r][0]] = cpu_to_le16(uc_word_table[r][1]); return uc; -- cgit v1.2.3 From 80119ef5c8153e0a6cc5edf00c083dc98a9bd348 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 May 2008 13:04:31 -0700 Subject: mm: fix atomic_t overflow in vm The atomic_t type is 32bit but a 64bit system can have more than 2^32 pages of virtual address space available. Without this we overflow on ludicrously large mappings Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/proc_misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 74a323d2b85..32dc14cd890 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -139,7 +139,7 @@ static int meminfo_read_proc(char *page, char **start, off_t off, #define K(x) ((x) << (PAGE_SHIFT - 10)) si_meminfo(&i); si_swapinfo(&i); - committed = atomic_read(&vm_committed_space); + committed = atomic_long_read(&vm_committed_space); allowed = ((totalram_pages - hugetlb_total_pages()) * sysctl_overcommit_ratio / 100) + total_swap_pages; -- cgit v1.2.3 From c4185a0e019387f5ad6e99009804965531fa1fab Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 23 May 2008 13:04:47 -0700 Subject: proc: proc_get_inode() should get module only once Any file under /proc/net opened more than once leaked the refcounter on the module it belongs to. The problem is that module_get is called for each file opening while module_put is called only when /proc inode is destroyed. So, lets put module counter if we are dealing with already initialised inode. Addresses http://bugzilla.kernel.org/show_bug.cgi?id=10737 Signed-off-by: Denis V. Lunev Cc: David Miller Cc: Patrick McHardy Acked-by: Pavel Emelyanov Acked-by: Robert Olsson Acked-by: Eric W. Biederman Reported-by: Roland Kletzing Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 6f4e8dc97da..b08d1001791 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -425,7 +425,8 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, } } unlock_new_inode(inode); - } + } else + module_put(de->owner); return inode; out_ino: -- cgit v1.2.3 From 5132861a7a44498ebb18357473f8b8d4cdc70e9f Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 22 May 2008 09:33:34 -0400 Subject: disable most mode changes on non-unix/non-cifsacl mounts CIFS currently allows you to change the mode of an inode on a share that doesn't have unix extensions enabled, and isn't using cifsacl. The inode in this case *only* has its mode changed in memory on the client. This is problematic since it can change any time the inode is purged from the cache. This patch makes cifs_setattr silently ignore most mode changes when unix extensions and cifsacl support are not enabled, and when the share is not mounted with the "dynperm" option. The exceptions are: When a mode change would remove all write access to an inode we turn on the ATTR_READONLY bit on the server and remove all write bits from the inode's mode in memory. When a mode change would add a write bit to an inode that previously had them all turned off, it turns off the ATTR_READONLY bit on the server, and resets the mode back to what it would normally be (generally, the file_mode or dir_mode of the share). Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/inode.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index fe752fdb26c..722be543cee 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1575,7 +1575,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) attrs->ia_valid &= ~ATTR_MODE; if (attrs->ia_valid & ATTR_MODE) { - cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); + cFYI(1, ("Mode changed to 0%o", attrs->ia_mode)); mode = attrs->ia_mode; } @@ -1590,18 +1590,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) #ifdef CONFIG_CIFS_EXPERIMENTAL if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) rc = mode_to_acl(inode, full_path, mode); - else if ((mode & S_IWUGO) == 0) { -#else - if ((mode & S_IWUGO) == 0) { + else #endif - /* not writeable */ - if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) { - set_dosattr = true; - time_buf.Attributes = - cpu_to_le32(cifsInode->cifsAttrs | - ATTR_READONLY); - } - } else if (cifsInode->cifsAttrs & ATTR_READONLY) { + if (((mode & S_IWUGO) == 0) && + (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { + set_dosattr = true; + time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs | + ATTR_READONLY); + /* fix up mode if we're not using dynperm */ + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) + attrs->ia_mode = inode->i_mode & ~S_IWUGO; + } else if ((mode & S_IWUGO) && + (cifsInode->cifsAttrs & ATTR_READONLY)) { /* If file is readonly on server, we would not be able to write to it - so if any write bit is enabled for user or group or other we @@ -1612,6 +1612,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) /* Windows ignores set to zero */ if (time_buf.Attributes == 0) time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL); + + /* reset local inode permissions to normal */ + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { + attrs->ia_mode &= ~(S_IALLUGO); + if (S_ISDIR(inode->i_mode)) + attrs->ia_mode |= + cifs_sb->mnt_dir_mode; + else + attrs->ia_mode |= + cifs_sb->mnt_file_mode; + } + } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { + /* ignore mode change - ATTR_READONLY hasn't changed */ + attrs->ia_valid &= ~ATTR_MODE; } } -- cgit v1.2.3 From 03cddb80ed2dacaf03c370d38bcc75f8303a03b8 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 5 Jun 2008 20:59:29 -0400 Subject: ext4: Fix use of uninitialized data with debug enabled. Fix use of uninitialized data with debug enabled. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/mballoc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 873ad9b3418..c9900aade15 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2745,8 +2745,6 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, sbi = EXT4_SB(sb); es = sbi->s_es; - ext4_debug("using block group %lu(%d)\n", ac->ac_b_ex.fe_group, - gdp->bg_free_blocks_count); err = -EIO; bitmap_bh = read_block_bitmap(sb, ac->ac_b_ex.fe_group); @@ -2762,6 +2760,9 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, if (!gdp) goto out_err; + ext4_debug("using block group %lu(%d)\n", ac->ac_b_ex.fe_group, + gdp->bg_free_blocks_count); + err = ext4_journal_get_write_access(handle, gdp_bh); if (err) goto out_err; @@ -3094,8 +3095,7 @@ static void ext4_mb_use_inode_pa(struct ext4_allocation_context *ac, static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac, struct ext4_prealloc_space *pa) { - unsigned len = ac->ac_o_ex.fe_len; - + unsigned int len = ac->ac_o_ex.fe_len; ext4_get_group_no_and_offset(ac->ac_sb, pa->pa_pstart, &ac->ac_b_ex.fe_group, &ac->ac_b_ex.fe_start); -- cgit v1.2.3 From 0bf7e8379ce7e0159a2a6bd3d937f2f6ada79799 Mon Sep 17 00:00:00 2001 From: "Jose R. Santos" Date: Tue, 3 Jun 2008 14:07:29 -0400 Subject: ext4: Fix uninit block group initialization with FLEX_BG With FLEX_BG block bitmaps, inode bitmaps and inode tables _MAY_ be allocated outside the group. So, when initializing an uninitialized block bitmap, we need to check the location of this blocks before setting the corresponding bits in the block bitmap of the newly initialized group. Also return the right number of free blocks when counting the available free blocks in uninit group. Tested-by: Aneesh Kumar K.V Signed-off-by: Jose R. Santos Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/balloc.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 30494c5da84..9cc80b9cc8d 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -43,6 +43,46 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, } +static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block, + ext4_group_t block_group) +{ + ext4_group_t actual_group; + ext4_get_group_no_and_offset(sb, block, &actual_group, 0); + if (actual_group == block_group) + return 1; + return 0; +} + +static int ext4_group_used_meta_blocks(struct super_block *sb, + ext4_group_t block_group) +{ + ext4_fsblk_t tmp; + struct ext4_sb_info *sbi = EXT4_SB(sb); + /* block bitmap, inode bitmap, and inode table blocks */ + int used_blocks = sbi->s_itb_per_group + 2; + + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { + struct ext4_group_desc *gdp; + struct buffer_head *bh; + + gdp = ext4_get_group_desc(sb, block_group, &bh); + if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp), + block_group)) + used_blocks--; + + if (!ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp), + block_group)) + used_blocks--; + + tmp = ext4_inode_table(sb, gdp); + for (; tmp < ext4_inode_table(sb, gdp) + + sbi->s_itb_per_group; tmp++) { + if (!ext4_block_in_group(sb, tmp, block_group)) + used_blocks -= 1; + } + } + return used_blocks; +} /* Initializes an uninitialized block bitmap if given, and returns the * number of blocks free in the group. */ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, @@ -105,20 +145,34 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, free_blocks = group_blocks - bit_max; if (bh) { - ext4_fsblk_t start; + ext4_fsblk_t start, tmp; + int flex_bg = 0; for (bit = 0; bit < bit_max; bit++) ext4_set_bit(bit, bh->b_data); start = ext4_group_first_block_no(sb, block_group); - /* Set bits for block and inode bitmaps, and inode table */ - ext4_set_bit(ext4_block_bitmap(sb, gdp) - start, bh->b_data); - ext4_set_bit(ext4_inode_bitmap(sb, gdp) - start, bh->b_data); - for (bit = (ext4_inode_table(sb, gdp) - start), - bit_max = bit + sbi->s_itb_per_group; bit < bit_max; bit++) - ext4_set_bit(bit, bh->b_data); + if (EXT4_HAS_INCOMPAT_FEATURE(sb, + EXT4_FEATURE_INCOMPAT_FLEX_BG)) + flex_bg = 1; + /* Set bits for block and inode bitmaps, and inode table */ + tmp = ext4_block_bitmap(sb, gdp); + if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) + ext4_set_bit(tmp - start, bh->b_data); + + tmp = ext4_inode_bitmap(sb, gdp); + if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) + ext4_set_bit(tmp - start, bh->b_data); + + tmp = ext4_inode_table(sb, gdp); + for (; tmp < ext4_inode_table(sb, gdp) + + sbi->s_itb_per_group; tmp++) { + if (!flex_bg || + ext4_block_in_group(sb, tmp, block_group)) + ext4_set_bit(tmp - start, bh->b_data); + } /* * Also if the number of blocks within the group is * less than the blocksize * 8 ( which is the size @@ -126,8 +180,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, */ mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data); } - - return free_blocks - sbi->s_itb_per_group - 2; + return free_blocks - ext4_group_used_meta_blocks(sb, block_group); } -- cgit v1.2.3 From 944600930a37aa725ba6f93c3244e2d77a1e3581 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 6 Jun 2008 18:05:52 -0400 Subject: ext4: fix online resize bug There is a bug when we are trying to verify that the reserve inode's double indirect blocks point back to the primary gdt blocks. The fix is obvious, we need to mod the gdb count by the addr's per block. This was verified using the same testcase as with the ext3 equivalent of this patch. Signed-off-by: Josef Bacik Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/resize.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 9f086a6a472..9ecb92f6854 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -563,7 +563,8 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, } blk = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + EXT4_SB(sb)->s_gdb_count; - data = (__le32 *)dind->b_data + EXT4_SB(sb)->s_gdb_count; + data = (__le32 *)dind->b_data + (EXT4_SB(sb)->s_gdb_count % + EXT4_ADDR_PER_BLOCK(sb)); end = (__le32 *)dind->b_data + EXT4_ADDR_PER_BLOCK(sb); /* Get each reserved primary GDT block and verify it holds backups */ -- cgit v1.2.3 From 8ea76900be3b4522396e2021260d2818a27b3a5b Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 26 May 2008 10:28:09 -0400 Subject: jbd2: Fix memory leak when verifying checksums in the journal Cc: Andreas Dilger Cc: Girish Shilamkar Signed-off-by: "Theodore Ts'o" --- fs/jbd2/recovery.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs') diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 5d0405a9e7c..7199db52b2f 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -344,6 +344,7 @@ static int calc_chksums(journal_t *journal, struct buffer_head *bh, *crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data, obh->b_size); } + put_bh(obh); } return 0; } -- cgit v1.2.3 From 624080eded68738daee041ad64672a9d2614754f Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 6 Jun 2008 17:50:40 -0400 Subject: jbd2: If a journal checksum error is detected, propagate the error to ext4 If a journal checksum error is detected, the ext4 filesystem will call ext4_error(), and the mount will either continue, become a read-only mount, or cause a kernel panic based on the superblock flags indicating the user's preference of what to do in case of filesystem corruption being detected. Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 23 +++++++++++++++++++++++ fs/jbd2/recovery.c | 11 ++++------- 2 files changed, 27 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 09d9359c805..d01a32e8b50 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2189,6 +2189,29 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) { if (ext4_load_journal(sb, es, journal_devnum)) goto failed_mount3; + if (!(sb->s_flags & MS_RDONLY) && + EXT4_SB(sb)->s_journal->j_failed_commit) { + printk(KERN_CRIT "EXT4-fs error (device %s): " + "ext4_fill_super: Journal transaction " + "%u is corrupt\n", sb->s_id, + EXT4_SB(sb)->s_journal->j_failed_commit); + if (test_opt (sb, ERRORS_RO)) { + printk (KERN_CRIT + "Mounting filesystem read-only\n"); + sb->s_flags |= MS_RDONLY; + EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; + es->s_state |= cpu_to_le16(EXT4_ERROR_FS); + } + if (test_opt(sb, ERRORS_PANIC)) { + EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; + es->s_state |= cpu_to_le16(EXT4_ERROR_FS); + ext4_commit_super(sb, es, 1); + printk(KERN_CRIT + "EXT4-fs (device %s): mount failed\n", + sb->s_id); + goto failed_mount4; + } + } } else if (journal_inum) { if (ext4_create_journal(sb, es, journal_inum)) goto failed_mount3; diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 7199db52b2f..058f50f65b7 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -611,9 +611,8 @@ static int do_one_pass(journal_t *journal, chksum_err = chksum_seen = 0; if (info->end_transaction) { - printk(KERN_ERR "JBD: Transaction %u " - "found to be corrupt.\n", - next_commit_ID - 1); + journal->j_failed_commit = + info->end_transaction; brelse(bh); break; } @@ -644,10 +643,8 @@ static int do_one_pass(journal_t *journal, if (!JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)){ - printk(KERN_ERR - "JBD: Transaction %u " - "found to be corrupt.\n", - next_commit_ID); + journal->j_failed_commit = + next_commit_ID; brelse(bh); break; } -- cgit v1.2.3 From cd0b6a39a1d68b61b1073662f40f747c8b728f98 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 26 May 2008 10:28:28 -0400 Subject: ext4: Display the journal_async_commit mount option in /proc/mounts Cc: Andreas Dilger Cc: Girish Shilamkar Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/ext4/super.c b/fs/ext4/super.c index d01a32e8b50..ba92c606ad9 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -731,6 +731,8 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) } if (test_opt(sb, BARRIER)) seq_puts(seq, ",barrier=1"); + if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) + seq_puts(seq, ",journal_async_commit"); if (test_opt(sb, NOBH)) seq_puts(seq, ",nobh"); if (!test_opt(sb, EXTENTS)) -- cgit v1.2.3 From 034772b068be62a79470d6c1b81b01fbe27793ac Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 3 Jun 2008 22:31:11 -0400 Subject: jbd2: Fix barrier fallback code to re-lock the buffer head If the device doesn't support write barriers, the write is retried without ordered mode. But the buffer head needs to be re-locked or submit_bh will fail with on BUG(!buffer_locked(bh)). Signed-off-by: "Theodore Ts'o" --- fs/jbd2/commit.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs') diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 4d99685fdce..a2ed72f7cee 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -168,6 +168,7 @@ static int journal_submit_commit_record(journal_t *journal, spin_unlock(&journal->j_state_lock); /* And try again, without the barrier */ + lock_buffer(bh); set_buffer_uptodate(bh); set_buffer_dirty(bh); ret = submit_bh(WRITE, bh); -- cgit v1.2.3 From 571640cad3fda6475da45d91cf86076f1f86bd9b Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 26 May 2008 12:29:46 -0400 Subject: ext4: enable barriers by default I can't think of any valid reason for ext4 to not use barriers when they are available; I believe this is necessary for filesystem integrity in the face of a volatile write cache on storage. An administrator who trusts that the cache is sufficiently battery- backed (and power supplies are sufficiently redundant, etc...) can always turn it back off again. SuSE has carried such a patch for ext3 for quite some time now. Also document the mount option while we're at it. Signed-off-by: Eric Sandeen Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/ext4/super.c b/fs/ext4/super.c index ba92c606ad9..cb96f127c36 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -671,6 +671,7 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) unsigned long def_mount_opts; struct super_block *sb = vfs->mnt_sb; struct ext4_sb_info *sbi = EXT4_SB(sb); + journal_t *journal = sbi->s_journal; struct ext4_super_block *es = sbi->s_es; def_mount_opts = le32_to_cpu(es->s_default_mount_opts); @@ -729,8 +730,13 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) seq_printf(seq, ",commit=%u", (unsigned) (sbi->s_commit_interval / HZ)); } - if (test_opt(sb, BARRIER)) - seq_puts(seq, ",barrier=1"); + /* + * We're changing the default of barrier mount option, so + * let's always display its mount state so it's clear what its + * status is. + */ + seq_puts(seq, ",barrier="); + seq_puts(seq, test_opt(sb, BARRIER) ? "1" : "0"); if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) seq_puts(seq, ",journal_async_commit"); if (test_opt(sb, NOBH)) @@ -1909,6 +1915,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) sbi->s_resgid = le16_to_cpu(es->s_def_resgid); set_opt(sbi->s_mount_opt, RESERVATION); + set_opt(sbi->s_mount_opt, BARRIER); /* * turn on extents feature by default in ext4 filesystem -- cgit v1.2.3 From cbaffba12ce08beb3e80bfda148ee0fa14aac188 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 26 May 2008 20:55:42 +0400 Subject: posix timers: discard SI_TIMER signals on exec Based on Roland's patch. This approach was suggested by Austin Clements from the very beginning, and then by Linus. As Austin pointed out, the execing task can be killed by SI_TIMER signal because exec flushes the signal handlers, but doesn't discard the pending signals generated by posix timers. Perhaps not a bug, but people find this surprising. See http://bugzilla.kernel.org/show_bug.cgi?id=10460 Signed-off-by: Oleg Nesterov Cc: Austin Clements Cc: Roland McGrath Signed-off-by: Linus Torvalds --- fs/exec.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs') diff --git a/fs/exec.c b/fs/exec.c index 3c2ba7ce11d..9448f1b50b4 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -860,6 +860,7 @@ static int de_thread(struct task_struct *tsk) no_thread_group: exit_itimers(sig); + flush_itimer_signals(); if (leader) release_task(leader); -- cgit v1.2.3 From a82c53a0e3f57f02782330372b7adad67b417645 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Fri, 9 May 2008 13:28:36 +0200 Subject: splice: fix sendfile() issue with relay Splice isn't always incrementing the ppos correctly, which broke relay splice. Signed-off-by: Tom Zanussi Tested-by: Dan Williams Signed-off-by: Jens Axboe --- fs/splice.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/splice.c b/fs/splice.c index 78150038b58..a048ad2130c 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -983,7 +983,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, while (len) { size_t read_len; - loff_t pos = sd->pos; + loff_t pos = sd->pos, prev_pos = pos; ret = do_splice_to(in, &pos, pipe, len, flags); if (unlikely(ret <= 0)) @@ -998,15 +998,19 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, * could get stuck data in the internal pipe: */ ret = actor(pipe, sd); - if (unlikely(ret <= 0)) + if (unlikely(ret <= 0)) { + sd->pos = prev_pos; goto out_release; + } bytes += ret; len -= ret; sd->pos = pos; - if (ret < read_len) + if (ret < read_len) { + sd->pos = prev_pos + ret; goto out_release; + } } done: @@ -1072,7 +1076,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, ret = splice_direct_to_actor(in, &sd, direct_splice_actor); if (ret > 0) - *ppos += ret; + *ppos = sd.pos; return ret; } -- cgit v1.2.3 From ca39d651d17df49b6d11f851d56c0ce0ce01ea1a Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 20 May 2008 21:27:41 +0200 Subject: splice: handle try_to_release_page() failure splice currently assumes that try_to_release_page() always suceeds, but it can return failure. If it does, we cannot steal the page. Acked-by: Mingming Cao --- fs/splice.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/splice.c b/fs/splice.c index a048ad2130c..aa5f6f60b30 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -58,8 +58,8 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe, */ wait_on_page_writeback(page); - if (PagePrivate(page)) - try_to_release_page(page, GFP_KERNEL); + if (PagePrivate(page) && !try_to_release_page(page, GFP_KERNEL)) + goto out_unlock; /* * If we succeeded in removing the mapping, set LRU flag @@ -75,6 +75,7 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe, * Raced with truncate or failed to remove page from current * address space, unlock and return failure. */ +out_unlock: unlock_page(page); return 1; } -- cgit v1.2.3 From a12630b186d56a77d17c9b34c82b88dda4337ed7 Mon Sep 17 00:00:00 2001 From: Joel Becker Date: Fri, 9 May 2008 18:49:29 -0700 Subject: ocfs2: Rename 'user_stack' plugin structure to 'ocfs2_user_plugin' The static structure describing the userspace cluster plugin for ocfs2 was named 'user_stack', which is a real pain when people are grep(1)ing the tree for the program stack object 'user_stack'. Change the name to something distinct and namespaced. Signed-off-by: Joel Becker Signed-off-by: Mark Fasheh --- fs/ocfs2/stack_user.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index b503772cd0e..6b97d11f6bf 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c @@ -61,7 +61,7 @@ * negotiated by the client. The client negotiates based on the maximum * version advertised in /sys/fs/ocfs2/max_locking_protocol. The major * number from the "SETV" message must match - * user_stack.sp_proto->lp_max_version.pv_major, and the minor number + * ocfs2_user_plugin.sp_proto->lp_max_version.pv_major, and the minor number * must be less than or equal to ...->lp_max_version.pv_minor. * * Once this information has been set, mounts will be allowed. From this @@ -153,7 +153,7 @@ union ocfs2_control_message { struct ocfs2_control_message_down u_down; }; -static struct ocfs2_stack_plugin user_stack; +static struct ocfs2_stack_plugin ocfs2_user_plugin; static atomic_t ocfs2_control_opened; static int ocfs2_control_this_node = -1; @@ -399,7 +399,7 @@ static int ocfs2_control_do_setversion_msg(struct file *file, char *ptr = NULL; struct ocfs2_control_private *p = file->private_data; struct ocfs2_protocol_version *max = - &user_stack.sp_proto->lp_max_version; + &ocfs2_user_plugin.sp_proto->lp_max_version; if (ocfs2_control_get_handshake_state(file) != OCFS2_CONTROL_HANDSHAKE_PROTOCOL) @@ -680,7 +680,7 @@ static void fsdlm_lock_ast_wrapper(void *astarg) struct dlm_lksb *lksb = fsdlm_astarg_to_lksb(astarg); int status = lksb->sb_status; - BUG_ON(user_stack.sp_proto == NULL); + BUG_ON(ocfs2_user_plugin.sp_proto == NULL); /* * For now we're punting on the issue of other non-standard errors @@ -693,16 +693,16 @@ static void fsdlm_lock_ast_wrapper(void *astarg) */ if (status == -DLM_EUNLOCK || status == -DLM_ECANCEL) - user_stack.sp_proto->lp_unlock_ast(astarg, 0); + ocfs2_user_plugin.sp_proto->lp_unlock_ast(astarg, 0); else - user_stack.sp_proto->lp_lock_ast(astarg); + ocfs2_user_plugin.sp_proto->lp_lock_ast(astarg); } static void fsdlm_blocking_ast_wrapper(void *astarg, int level) { - BUG_ON(user_stack.sp_proto == NULL); + BUG_ON(ocfs2_user_plugin.sp_proto == NULL); - user_stack.sp_proto->lp_blocking_ast(astarg, level); + ocfs2_user_plugin.sp_proto->lp_blocking_ast(astarg, level); } static int user_dlm_lock(struct ocfs2_cluster_connection *conn, @@ -838,7 +838,7 @@ static int user_cluster_this_node(unsigned int *this_node) return 0; } -static struct ocfs2_stack_operations user_stack_ops = { +static struct ocfs2_stack_operations ocfs2_user_plugin_ops = { .connect = user_cluster_connect, .disconnect = user_cluster_disconnect, .this_node = user_cluster_this_node, @@ -849,20 +849,20 @@ static struct ocfs2_stack_operations user_stack_ops = { .dump_lksb = user_dlm_dump_lksb, }; -static struct ocfs2_stack_plugin user_stack = { +static struct ocfs2_stack_plugin ocfs2_user_plugin = { .sp_name = "user", - .sp_ops = &user_stack_ops, + .sp_ops = &ocfs2_user_plugin_ops, .sp_owner = THIS_MODULE, }; -static int __init user_stack_init(void) +static int __init ocfs2_user_plugin_init(void) { int rc; rc = ocfs2_control_init(); if (!rc) { - rc = ocfs2_stack_glue_register(&user_stack); + rc = ocfs2_stack_glue_register(&ocfs2_user_plugin); if (rc) ocfs2_control_exit(); } @@ -870,14 +870,14 @@ static int __init user_stack_init(void) return rc; } -static void __exit user_stack_exit(void) +static void __exit ocfs2_user_plugin_exit(void) { - ocfs2_stack_glue_unregister(&user_stack); + ocfs2_stack_glue_unregister(&ocfs2_user_plugin); ocfs2_control_exit(); } MODULE_AUTHOR("Oracle"); MODULE_DESCRIPTION("ocfs2 driver for userspace cluster stacks"); MODULE_LICENSE("GPL"); -module_init(user_stack_init); -module_exit(user_stack_exit); +module_init(ocfs2_user_plugin_init); +module_exit(ocfs2_user_plugin_exit); -- cgit v1.2.3 From 271d772d02507c7541d5e6b4938ed2380e59a39a Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Mon, 12 May 2008 18:31:35 -0700 Subject: [PATCH 1/3] ocfs2/net: Silence build warnings This patch silences the build warnings concerning o2net_debugfs_init() and friends when building without CONFIG_DEBUG_FS enabled. Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh --- fs/ocfs2/cluster/tcp.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/ocfs2/cluster/tcp.h b/fs/ocfs2/cluster/tcp.h index a705d5d1903..fd6179eb26d 100644 --- a/fs/ocfs2/cluster/tcp.h +++ b/fs/ocfs2/cluster/tcp.h @@ -128,23 +128,23 @@ void o2net_debug_del_nst(struct o2net_send_tracking *nst); void o2net_debug_add_sc(struct o2net_sock_container *sc); void o2net_debug_del_sc(struct o2net_sock_container *sc); #else -static int o2net_debugfs_init(void) +static inline int o2net_debugfs_init(void) { return 0; } -static void o2net_debugfs_exit(void) +static inline void o2net_debugfs_exit(void) { } -static void o2net_debug_add_nst(struct o2net_send_tracking *nst) +static inline void o2net_debug_add_nst(struct o2net_send_tracking *nst) { } -static void o2net_debug_del_nst(struct o2net_send_tracking *nst) +static inline void o2net_debug_del_nst(struct o2net_send_tracking *nst) { } -static void o2net_debug_add_sc(struct o2net_sock_container *sc) +static inline void o2net_debug_add_sc(struct o2net_sock_container *sc) { } -static void o2net_debug_del_sc(struct o2net_sock_container *sc) +static inline void o2net_debug_del_sc(struct o2net_sock_container *sc) { } #endif /* CONFIG_DEBUG_FS */ -- cgit v1.2.3 From 959040c37a8cae8117907d4aed87f1b01ff1ea19 Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Mon, 12 May 2008 18:31:36 -0700 Subject: [PATCH 2/3] ocfs2/dlm: Silence build warnings This patch silences the build warnings concerning dlm_debug_init() and friends when building without CONFIG_DEBUG_FS enabled. Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh --- fs/ocfs2/dlm/dlmdebug.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/ocfs2/dlm/dlmdebug.h b/fs/ocfs2/dlm/dlmdebug.h index d34a62a3a62..8c686d22f9c 100644 --- a/fs/ocfs2/dlm/dlmdebug.h +++ b/fs/ocfs2/dlm/dlmdebug.h @@ -60,25 +60,25 @@ void dlm_destroy_debugfs_root(void); #else -static int dlm_debug_init(struct dlm_ctxt *dlm) +static inline int dlm_debug_init(struct dlm_ctxt *dlm) { return 0; } -static void dlm_debug_shutdown(struct dlm_ctxt *dlm) +static inline void dlm_debug_shutdown(struct dlm_ctxt *dlm) { } -static int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm) +static inline int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm) { return 0; } -static void dlm_destroy_debugfs_subroot(struct dlm_ctxt *dlm) +static inline void dlm_destroy_debugfs_subroot(struct dlm_ctxt *dlm) { } -static int dlm_create_debugfs_root(void) +static inline int dlm_create_debugfs_root(void) { return 0; } -static void dlm_destroy_debugfs_root(void) +static inline void dlm_destroy_debugfs_root(void) { } -- cgit v1.2.3 From 0f475b2abed6cbccee1da20a0bef2895eb2a0edd Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Mon, 12 May 2008 18:31:37 -0700 Subject: [PATCH 3/3] ocfs2/net: Silence build warnings This patch silences the build warnings concerning o2net_init_nst() and friends when building without CONFIG_DEBUG_FS enabled. Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh --- fs/ocfs2/cluster/tcp.c | 28 +++++++++------------------- fs/ocfs2/cluster/tcp_internal.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 19 deletions(-) (limited to 'fs') diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 1e44ad14881..a27d61581bd 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -142,53 +142,43 @@ static void o2net_idle_timer(unsigned long data); static void o2net_sc_postpone_idle(struct o2net_sock_container *sc); static void o2net_sc_reset_idle_timer(struct o2net_sock_container *sc); -static void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, - u32 msgkey, struct task_struct *task, u8 node) -{ #ifdef CONFIG_DEBUG_FS +void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, + u32 msgkey, struct task_struct *task, u8 node) +{ INIT_LIST_HEAD(&nst->st_net_debug_item); nst->st_task = task; nst->st_msg_type = msgtype; nst->st_msg_key = msgkey; nst->st_node = node; -#endif } -static void o2net_set_nst_sock_time(struct o2net_send_tracking *nst) +void o2net_set_nst_sock_time(struct o2net_send_tracking *nst) { -#ifdef CONFIG_DEBUG_FS do_gettimeofday(&nst->st_sock_time); -#endif } -static void o2net_set_nst_send_time(struct o2net_send_tracking *nst) +void o2net_set_nst_send_time(struct o2net_send_tracking *nst) { -#ifdef CONFIG_DEBUG_FS do_gettimeofday(&nst->st_send_time); -#endif } -static void o2net_set_nst_status_time(struct o2net_send_tracking *nst) +void o2net_set_nst_status_time(struct o2net_send_tracking *nst) { -#ifdef CONFIG_DEBUG_FS do_gettimeofday(&nst->st_status_time); -#endif } -static void o2net_set_nst_sock_container(struct o2net_send_tracking *nst, +void o2net_set_nst_sock_container(struct o2net_send_tracking *nst, struct o2net_sock_container *sc) { -#ifdef CONFIG_DEBUG_FS nst->st_sc = sc; -#endif } -static void o2net_set_nst_msg_id(struct o2net_send_tracking *nst, u32 msg_id) +void o2net_set_nst_msg_id(struct o2net_send_tracking *nst, u32 msg_id) { -#ifdef CONFIG_DEBUG_FS nst->st_id = msg_id; -#endif } +#endif /* CONFIG_DEBUG_FS */ static inline int o2net_reconnect_delay(void) { diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h index 8d58cfe410b..18307ff81b7 100644 --- a/fs/ocfs2/cluster/tcp_internal.h +++ b/fs/ocfs2/cluster/tcp_internal.h @@ -224,10 +224,42 @@ struct o2net_send_tracking { struct timeval st_send_time; struct timeval st_status_time; }; + +void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, + u32 msgkey, struct task_struct *task, u8 node); +void o2net_set_nst_sock_time(struct o2net_send_tracking *nst); +void o2net_set_nst_send_time(struct o2net_send_tracking *nst); +void o2net_set_nst_status_time(struct o2net_send_tracking *nst); +void o2net_set_nst_sock_container(struct o2net_send_tracking *nst, + struct o2net_sock_container *sc); +void o2net_set_nst_msg_id(struct o2net_send_tracking *nst, u32 msg_id); + #else struct o2net_send_tracking { u32 dummy; }; + +static inline void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, + u32 msgkey, struct task_struct *task, u8 node) +{ +} +static inline void o2net_set_nst_sock_time(struct o2net_send_tracking *nst) +{ +} +static inline void o2net_set_nst_send_time(struct o2net_send_tracking *nst) +{ +} +static inline void o2net_set_nst_status_time(struct o2net_send_tracking *nst) +{ +} +static inline void o2net_set_nst_sock_container(struct o2net_send_tracking *nst, + struct o2net_sock_container *sc) +{ +} +static inline void o2net_set_nst_msg_id(struct o2net_send_tracking *nst, + u32 msg_id) +{ +} #endif /* CONFIG_DEBUG_FS */ #endif /* O2CLUSTER_TCP_INTERNAL_H */ -- cgit v1.2.3 From ca05a99a54db1db5bca72eccb5866d2a86f8517f Mon Sep 17 00:00:00 2001 From: "Andrew G. Morgan" Date: Tue, 27 May 2008 22:05:17 -0700 Subject: capabilities: remain source compatible with 32-bit raw legacy capability support. Source code out there hard-codes a notion of what the _LINUX_CAPABILITY_VERSION #define means in terms of the semantics of the raw capability system calls capget() and capset(). Its unfortunate, but true. Since the confusing header file has been in a released kernel, there is software that is erroneously using 64-bit capabilities with the semantics of 32-bit compatibilities. These recently compiled programs may suffer corruption of their memory when sys_getcap() overwrites more memory than they are coded to expect, and the raising of added capabilities when using sys_capset(). As such, this patch does a number of things to clean up the situation for all. It 1. forces the _LINUX_CAPABILITY_VERSION define to always retain its legacy value. 2. adopts a new #define strategy for the kernel's internal implementation of the preferred magic. 3. deprecates v2 capability magic in favor of a new (v3) magic number. The functionality of v3 is entirely equivalent to v2, the only difference being that the v2 magic causes the kernel to log a "deprecated" warning so the admin can find applications that may be using v2 inappropriately. [User space code continues to be encouraged to use the libcap API which protects the application from details like this. libcap-2.10 is the first to support v3 capabilities.] Fixes issue reported in https://bugzilla.redhat.com/show_bug.cgi?id=447518. Thanks to Bojan Smojver for the report. [akpm@linux-foundation.org: s/depreciate/deprecate/g] [akpm@linux-foundation.org: be robust about put_user size] [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Andrew G. Morgan Cc: Serge E. Hallyn Cc: Bojan Smojver Cc: stable@kernel.org Signed-off-by: Andrew Morton Signed-off-by: Chris Wright --- fs/proc/array.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/proc/array.c b/fs/proc/array.c index 9e3b8c33c24..797d775e035 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -288,7 +288,7 @@ static void render_cap_t(struct seq_file *m, const char *header, seq_printf(m, "%s", header); CAP_FOR_EACH_U32(__capi) { seq_printf(m, "%08x", - a->cap[(_LINUX_CAPABILITY_U32S-1) - __capi]); + a->cap[(_KERNEL_CAPABILITY_U32S-1) - __capi]); } seq_printf(m, "\n"); } -- cgit v1.2.3 From 1d92cfd54a51ff1b9593019fdde56793b66ba6a9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 2 Jun 2008 10:59:02 +0100 Subject: cifs endianness fixes __le16 fields used as host-endian. Signed-off-by: Al Viro Acked-by: Steve French Signed-off-by: Linus Torvalds --- fs/cifs/cifssmb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 9b8b4cfdf99..fb655b4593c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3927,9 +3927,9 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, } ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals); - if (ref->VersionNumber != 3) { + if (ref->VersionNumber != cpu_to_le16(3)) { cERROR(1, ("Referrals of V%d version are not supported," - "should be V3", ref->VersionNumber)); + "should be V3", le16_to_cpu(ref->VersionNumber))); rc = -EINVAL; goto parse_DFS_referrals_exit; } @@ -3977,7 +3977,7 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, if (rc) goto parse_DFS_referrals_exit; - ref += ref->Size; + ref += le16_to_cpu(ref->Size); } parse_DFS_referrals_exit: -- cgit v1.2.3 From ddb2c43594f22843e9f3153da151deaba1a834c5 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Wed, 4 Jun 2008 09:16:33 -0700 Subject: asn1: additional sanity checking during BER decoding - Don't trust a length which is greater than the working buffer. An invalid length could cause overflow when calculating buffer size for decoding oid. - An oid length of zero is invalid and allows for an off-by-one error when decoding oid because the first subid actually encodes first 2 subids. - A primitive encoding may not have an indefinite length. Thanks to Wei Wang from McAfee for report. Cc: Steven French Cc: stable@kernel.org Acked-by: Patrick McHardy Signed-off-by: Chris Wright Signed-off-by: Linus Torvalds --- fs/cifs/asn1.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'fs') diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index cb52cbbe45f..f58e41d3ba4 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -186,6 +186,11 @@ asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len) } } } + + /* don't trust len bigger than ctx buffer */ + if (*len > ctx->end - ctx->pointer) + return 0; + return 1; } @@ -203,6 +208,10 @@ asn1_header_decode(struct asn1_ctx *ctx, if (!asn1_length_decode(ctx, &def, &len)) return 0; + /* primitive shall be definite, indefinite shall be constructed */ + if (*con == ASN1_PRI && !def) + return 0; + if (def) *eoc = ctx->pointer + len; else @@ -389,6 +398,11 @@ asn1_oid_decode(struct asn1_ctx *ctx, unsigned long *optr; size = eoc - ctx->pointer + 1; + + /* first subid actually encodes first two subids */ + if (size < 2 || size > ULONG_MAX/sizeof(unsigned long)) + return 0; + *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); if (*oid == NULL) return 0; -- cgit v1.2.3 From b8c141e8fd80fa64d80c6a74492053f25a28e0ea Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 5 Jun 2008 22:45:55 -0700 Subject: frv: don't offer BINFMT_FLAT Fix the following compile error: CC fs/binfmt_flat.o In file included from /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c:36: /home/bunk/linux/kernel-2.6/git/linux-2.6/include/linux/flat.h:14:22: error: asm/flat.h: No such file or directory /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c: In function 'create_flat_tables': /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c:124: error: implicit declaration of function 'flat_stack_align' /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c:125: error: implicit declaration of function 'flat_argvp_envp_on_stack' /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c: In function 'calc_reloc': /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c:347: error: implicit declaration of function 'flat_reloc_valid' /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c: In function 'load_flat_file': /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c:479: error: implicit declaration of function 'flat_old_ram_flag' /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c:755: error: implicit declaration of function 'flat_set_persistent' /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c:757: error: implicit declaration of function 'flat_get_relocate_addr' /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c:765: error: implicit declaration of function 'flat_get_addr_from_rp' /home/bunk/linux/kernel-2.6/git/linux-2.6/fs/binfmt_flat.c:781: error: implicit declaration of function 'flat_put_addr_at_rp' Reported-by: Adrian Bunk Signed-off-by: Adrian Bunk Tested-by: David Howells Acked-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/Kconfig.binfmt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index 55e8ee1900a..3263084eef9 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -42,7 +42,7 @@ config BINFMT_ELF_FDPIC config BINFMT_FLAT bool "Kernel support for flat binaries" - depends on !MMU + depends on !MMU && (!FRV || BROKEN) help Support uClinux FLAT format binaries. -- cgit v1.2.3 From d3e49afbb66109613c3474f2273f5830ac2dcb09 Mon Sep 17 00:00:00 2001 From: Michael Halcrow Date: Thu, 5 Jun 2008 22:46:02 -0700 Subject: eCryptfs: remove unnecessary page decrypt call The page decrypt calls in ecryptfs_write() are both pointless and buggy. Pointless because ecryptfs_get_locked_page() has already brought the page up to date, and buggy because prior mmap writes will just be blown away by the decrypt call. This patch also removes the declaration of a now-nonexistent function ecryptfs_write_zeros(). Thanks to Eric Sandeen and David Kleikamp for helping to track this down. Eric said: fsx w/ mmap dies quickly ( < 100 ops) without this, and survives nicely (to millions of ops+) with it in place. Signed-off-by: Michael Halcrow Cc: Eric Sandeen Cc: Dave Kleikamp Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ecryptfs/ecryptfs_kernel.h | 2 -- fs/ecryptfs/read_write.c | 22 ---------------------- 2 files changed, 24 deletions(-) (limited to 'fs') diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index 951ee33a022..c15c25745e0 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -660,8 +660,6 @@ int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, struct ecryptfs_auth_tok **auth_tok, char *sig); -int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, - int num_zeros); int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data, loff_t offset, size_t size); int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode, diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c index ebf55150be5..75c2ea9fee3 100644 --- a/fs/ecryptfs/read_write.c +++ b/fs/ecryptfs/read_write.c @@ -157,20 +157,6 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset, ecryptfs_page_idx, rc); goto out; } - if (start_offset_in_page) { - /* Read in the page from the lower - * into the eCryptfs inode page cache, - * decrypting */ - rc = ecryptfs_decrypt_page(ecryptfs_page); - if (rc) { - printk(KERN_ERR "%s: Error decrypting " - "page; rc = [%d]\n", - __func__, rc); - ClearPageUptodate(ecryptfs_page); - page_cache_release(ecryptfs_page); - goto out; - } - } ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0); /* @@ -349,14 +335,6 @@ int ecryptfs_read(char *data, loff_t offset, size_t size, ecryptfs_page_idx, rc); goto out; } - rc = ecryptfs_decrypt_page(ecryptfs_page); - if (rc) { - printk(KERN_ERR "%s: Error decrypting " - "page; rc = [%d]\n", __func__, rc); - ClearPageUptodate(ecryptfs_page); - page_cache_release(ecryptfs_page); - goto out; - } ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0); memcpy((data + data_offset), ((char *)ecryptfs_page_virt + start_offset_in_page), -- cgit v1.2.3 From 44d1b980c72db0faf35adb082fb2208351803028 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 5 Jun 2008 22:46:18 -0700 Subject: Fix various old email addresses for dwmw2 Although if people have questions about ARCnet, perhaps it's _better_ for them to be mailing dwmw2@cam.ac.uk about it... Signed-off-by: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/afs/callback.c | 2 +- fs/afs/inode.c | 2 +- fs/afs/super.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/afs/callback.c b/fs/afs/callback.c index a78d5b236bb..587ef5123cd 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c @@ -8,7 +8,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Authors: David Woodhouse + * Authors: David Woodhouse * David Howells * */ diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 08db82e1343..bb47217f6a1 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -8,7 +8,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Authors: David Woodhouse + * Authors: David Woodhouse * David Howells * */ diff --git a/fs/afs/super.c b/fs/afs/super.c index 4b572b801d8..7e3faeef681 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -10,7 +10,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Authors: David Howells - * David Woodhouse + * David Woodhouse * */ -- cgit v1.2.3 From 93b071139a956e51c98cdefd50a47981a4eb852e Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Thu, 5 Jun 2008 22:46:21 -0700 Subject: introduce memory_read_from_buffer() This patch introduces memory_read_from_buffer(). The only difference between memory_read_from_buffer() and simple_read_from_buffer() is which address space the function copies to. simple_read_from_buffer copies to user space memory. memory_read_from_buffer copies to normal memory. Signed-off-by: Akinobu Mita Cc: Al Viro Cc: Doug Warzecha Cc: Zhang Rui Cc: Matt Domsch Cc: Abhay Salunke Cc: Greg Kroah-Hartman Cc: Markus Rechberger Cc: Kay Sievers Cc: Bob Moore Cc: Thomas Renninger Cc: Len Brown Cc: Benjamin Herrenschmidt Cc: "Antonino A. Daplas" Cc: Krzysztof Helt Cc: Geert Uytterhoeven Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: Peter Oberparleiter Cc: Michael Holzheu Cc: Brian King Cc: James E.J. Bottomley Cc: Andrew Vasquez Cc: Seokmann Ju Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/libfs.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'fs') diff --git a/fs/libfs.c b/fs/libfs.c index b004dfadd89..892d41cb338 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -528,6 +528,23 @@ ssize_t simple_read_from_buffer(void __user *to, size_t count, loff_t *ppos, return count; } +ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, + const void *from, size_t available) +{ + loff_t pos = *ppos; + + if (pos < 0) + return -EINVAL; + if (pos >= available) + return 0; + if (count > available - pos) + count = available - pos; + memcpy(to, from + pos, count); + *ppos = pos + count; + + return count; +} + /* * Transaction based IO. * The file expects a single write which triggers the transaction, and then @@ -800,6 +817,7 @@ EXPORT_SYMBOL(simple_statfs); EXPORT_SYMBOL(simple_sync_file); EXPORT_SYMBOL(simple_unlink); EXPORT_SYMBOL(simple_read_from_buffer); +EXPORT_SYMBOL(memory_read_from_buffer); EXPORT_SYMBOL(simple_transaction_get); EXPORT_SYMBOL(simple_transaction_read); EXPORT_SYMBOL(simple_transaction_release); -- cgit v1.2.3 From 7db9cfd380205f6b50afdc3bc3619f876a5eaf0d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 5 Jun 2008 22:46:27 -0700 Subject: devscgroup: check for device permissions at mount time Currently even if a task sits in an all-denied cgroup it can still mount any block device in any mode it wants. Put a proper check in do_open for block device to prevent this. Signed-off-by: Pavel Emelyanov Acked-by: Serge Hallyn Tested-by: Serge Hallyn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/block_dev.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/block_dev.c b/fs/block_dev.c index 7d822fae776..470c10ceb0f 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -928,9 +929,14 @@ static int do_open(struct block_device *bdev, struct file *file, int for_part) { struct module *owner = NULL; struct gendisk *disk; - int ret = -ENXIO; + int ret; int part; + ret = devcgroup_inode_permission(bdev->bd_inode, file->f_mode); + if (ret != 0) + return ret; + + ret = -ENXIO; file->f_mapping = bdev->bd_inode->i_mapping; lock_kernel(); disk = get_gendisk(bdev->bd_dev, &part); -- cgit v1.2.3 From aae8679b0ebcaa92f99c1c3cb0cd651594a43915 Mon Sep 17 00:00:00 2001 From: Thomas Tuttle Date: Thu, 5 Jun 2008 22:46:31 -0700 Subject: pagemap: fix bug in add_to_pagemap, require aligned-length reads of /proc/pid/pagemap Fix a bug in add_to_pagemap. Previously, since pm->out was a char *, put_user was only copying 1 byte of every PFN, resulting in the top 7 bytes of each PFN not being copied. By requiring that reads be a multiple of 8 bytes, I can make pm->out and pm->end u64*s instead of char*s, which makes put_user work properly, and also simplifies the logic in add_to_pagemap a bit. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Thomas Tuttle Cc: Matt Mackall Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) (limited to 'fs') diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 88717c0f941..17403629e33 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -496,7 +496,7 @@ const struct file_operations proc_clear_refs_operations = { }; struct pagemapread { - char __user *out, *end; + u64 __user *out, *end; }; #define PM_ENTRY_BYTES sizeof(u64) @@ -519,21 +519,11 @@ struct pagemapread { static int add_to_pagemap(unsigned long addr, u64 pfn, struct pagemapread *pm) { - /* - * Make sure there's room in the buffer for an - * entire entry. Otherwise, only copy part of - * the pfn. - */ - if (pm->out + PM_ENTRY_BYTES >= pm->end) { - if (copy_to_user(pm->out, &pfn, pm->end - pm->out)) - return -EFAULT; - pm->out = pm->end; - return PM_END_OF_BUFFER; - } - if (put_user(pfn, pm->out)) return -EFAULT; - pm->out += PM_ENTRY_BYTES; + pm->out++; + if (pm->out >= pm->end) + return PM_END_OF_BUFFER; return 0; } @@ -634,7 +624,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, ret = -EINVAL; /* file position must be aligned */ - if (*ppos % PM_ENTRY_BYTES) + if ((*ppos % PM_ENTRY_BYTES) || (count % PM_ENTRY_BYTES)) goto out_task; ret = 0; @@ -664,8 +654,8 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, goto out_pages; } - pm.out = buf; - pm.end = buf + count; + pm.out = (u64 *)buf; + pm.end = (u64 *)(buf + count); if (!ptrace_may_attach(task)) { ret = -EIO; @@ -690,9 +680,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, if (ret == PM_END_OF_BUFFER) ret = 0; /* don't need mmap_sem for these, but this looks cleaner */ - *ppos += pm.out - buf; + *ppos += (char *)pm.out - buf; if (!ret) - ret = pm.out - buf; + ret = (char *)pm.out - buf; } out_pages: -- cgit v1.2.3 From d100d148aa48df3b6ad526a48624f906695efe60 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Thu, 5 Jun 2008 22:46:46 -0700 Subject: nommu: fix ksize() abuse The nommu binfmt code uses ksize() for pointers returned from do_mmap() which is wrong. This converts the call-sites to use the nommu specific kobjsize() function which works as expected. Cc: Christoph Lameter Cc: Matt Mackall Acked-by: Paul Mundt Acked-by: David Howells Signed-off-by: Pekka Enberg Acked-by: Greg Ungerer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/binfmt_elf_fdpic.c | 2 +- fs/binfmt_flat.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index ddd35d87339..d051a32e627 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -390,7 +390,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, } /* expand the stack mapping to use up the entire allocation granule */ - fullsize = ksize((char *) current->mm->start_brk); + fullsize = kobjsize((char *) current->mm->start_brk); if (!IS_ERR_VALUE(do_mremap(current->mm->start_brk, stack_size, fullsize, 0, 0))) stack_size = fullsize; diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 3b40d45a3a1..2cb1acda3a8 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -548,7 +548,7 @@ static int load_flat_file(struct linux_binprm * bprm, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0); /* Remap to use all availabe slack region space */ if (realdatastart && (realdatastart < (unsigned long)-4096)) { - reallen = ksize((void *)realdatastart); + reallen = kobjsize((void *)realdatastart); if (reallen > len) { realdatastart = do_mremap(realdatastart, len, reallen, MREMAP_FIXED, realdatastart); @@ -600,7 +600,7 @@ static int load_flat_file(struct linux_binprm * bprm, PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); /* Remap to use all availabe slack region space */ if (textpos && (textpos < (unsigned long) -4096)) { - reallen = ksize((void *)textpos); + reallen = kobjsize((void *)textpos); if (reallen > len) { textpos = do_mremap(textpos, len, reallen, MREMAP_FIXED, textpos); @@ -683,7 +683,7 @@ static int load_flat_file(struct linux_binprm * bprm, */ current->mm->start_brk = datapos + data_len + bss_len; current->mm->brk = (current->mm->start_brk + 3) & ~3; - current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len; + current->mm->context.end_brk = memp + kobjsize((void *) memp) - stack_len; } if (flags & FLAT_FLAG_KTRACE) @@ -790,7 +790,7 @@ static int load_flat_file(struct linux_binprm * bprm, /* zero the BSS, BRK and stack areas */ memset((void*)(datapos + data_len), 0, bss_len + - (memp + ksize((void *) memp) - stack_len - /* end brk */ + (memp + kobjsize((void *) memp) - stack_len - /* end brk */ libinfo->lib_list[id].start_brk) + /* start brk */ stack_len); -- cgit v1.2.3 From 9bb91784de6618c955994b2d5be332fb68c87ef1 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 5 Jun 2008 22:46:47 -0700 Subject: ext3: fix online resize bug There is a bug when we are trying to verify that the reserve inode's double indirect blocks point back to the primary gdt blocks. The fix is obvious, we need to mod the gdb count by the addr's per block. You can verify this with the following test case dd if=/dev/zero of=disk1 seek=1024 count=1 bs=100M losetup /dev/loop1 disk1 pvcreate /dev/loop1 vgcreate loopvg1 /dev/loop1 lvcreate -l 100%VG loopvg1 -n looplv1 mkfs.ext3 -J size=64 -b 1024 /dev/loopvg1/looplv1 mount /dev/loopvg1/looplv1 /mnt/loop dd if=/dev/zero of=disk2 seek=1024 count=1 bs=50M losetup /dev/loop2 disk2 pvcreate /dev/loop2 vgextend loopvg1 /dev/loop2 lvextend -l 100%VG /dev/loopvg1/looplv1 resize2fs /dev/loopvg1/looplv1 without this patch the resize2fs fails, with it the resize2fs succeeds. Signed-off-by: Josef Bacik Acked-by: Andreas Dilger Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/resize.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 28cfd0b4052..77278e947e9 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -580,7 +580,8 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, } blk = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + EXT3_SB(sb)->s_gdb_count; - data = (__le32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count; + data = (__le32 *)dind->b_data + (EXT3_SB(sb)->s_gdb_count % + EXT3_ADDR_PER_BLOCK(sb)); end = (__le32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb); /* Get each reserved primary GDT block and verify it holds backups */ -- cgit v1.2.3 From aed5417593ad125283f35513573282139a8664b5 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Thu, 5 Jun 2008 22:46:53 -0700 Subject: proc: calculate the correct /proc/ link count This patch: commit e9720acd728a46cb40daa52c99a979f7c4ff195c Author: Pavel Emelyanov Date: Fri Mar 7 11:08:40 2008 -0800 [NET]: Make /proc/net a symlink on /proc/self/net (v3) introduced a /proc/self/net directory without bumping the corresponding link count for /proc/self. This patch replaces the static link count initializations with a call that counts the number of directory entries in the given pid_entry table whenever it is instantiated, and thus relieves the burden of manually keeping the two in sync. [akpm@linux-foundation.org: cleanup] Acked-by: Eric W. Biederman Cc: Pavel Emelyanov Signed-off-by: Vegard Nossum Cc: "David S. Miller" Cc: Alexey Dobriyan Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/proc/base.c b/fs/proc/base.c index c447e0743a3..3b455371e7f 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -127,6 +127,25 @@ struct pid_entry { NULL, &proc_single_file_operations, \ { .proc_show = &proc_##OTYPE } ) +/* + * Count the number of hardlinks for the pid_entry table, excluding the . + * and .. links. + */ +static unsigned int pid_entry_count_dirs(const struct pid_entry *entries, + unsigned int n) +{ + unsigned int i; + unsigned int count; + + count = 0; + for (i = 0; i < n; ++i) { + if (S_ISDIR(entries[i].mode)) + ++count; + } + + return count; +} + int maps_protect; EXPORT_SYMBOL(maps_protect); @@ -2585,10 +2604,9 @@ static struct dentry *proc_pid_instantiate(struct inode *dir, inode->i_op = &proc_tgid_base_inode_operations; inode->i_fop = &proc_tgid_base_operations; inode->i_flags|=S_IMMUTABLE; - inode->i_nlink = 5; -#ifdef CONFIG_SECURITY - inode->i_nlink += 1; -#endif + + inode->i_nlink = 2 + pid_entry_count_dirs(tgid_base_stuff, + ARRAY_SIZE(tgid_base_stuff)); dentry->d_op = &pid_dentry_operations; @@ -2816,10 +2834,9 @@ static struct dentry *proc_task_instantiate(struct inode *dir, inode->i_op = &proc_tid_base_inode_operations; inode->i_fop = &proc_tid_base_operations; inode->i_flags|=S_IMMUTABLE; - inode->i_nlink = 4; -#ifdef CONFIG_SECURITY - inode->i_nlink += 1; -#endif + + inode->i_nlink = 2 + pid_entry_count_dirs(tid_base_stuff, + ARRAY_SIZE(tid_base_stuff)); dentry->d_op = &pid_dentry_operations; -- cgit v1.2.3 From bbcdac0c20aa20d1daad41d9c138102b70e5aae4 Mon Sep 17 00:00:00 2001 From: Thomas Tuttle Date: Thu, 5 Jun 2008 22:46:58 -0700 Subject: pagemap: return map count, not reference count, in /proc/kpagecount Since pagemap is all about examining pages mapped into processes' memory spaces, it makes sense for kpagecount to return the map counts, not the reference counts. Signed-off-by: Thomas Tuttle Cc: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/proc_misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 32dc14cd890..5a16090a6d6 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -726,7 +726,7 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf, if (!ppage) pcount = 0; else - pcount = atomic_read(&ppage->_count); + pcount = page_mapcount(ppage); if (put_user(pcount, out++)) { ret = -EFAULT; -- cgit v1.2.3 From 4710d1ac4c491dd8a28f57946214c0b5fe73cc87 Mon Sep 17 00:00:00 2001 From: Thomas Tuttle Date: Thu, 5 Jun 2008 22:46:58 -0700 Subject: pagemap: return EINVAL, not EIO, for unaligned reads of kpagecount or kpageflags If the user tries to read from a position that is not a multiple of 8, or read a number of bytes that is not a multiple of 8, they have passed an invalid argument to read, for the purpose of reading these files. It's not an IO error because we didn't encounter any trouble finding the data they asked for. Signed-off-by: Thomas Tuttle Cc: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/proc_misc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 5a16090a6d6..7e277f2ad46 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -716,7 +716,7 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf, pfn = src / KPMSIZE; count = min_t(size_t, count, (max_pfn * KPMSIZE) - src); if (src & KPMMASK || count & KPMMASK) - return -EIO; + return -EINVAL; while (count > 0) { ppage = NULL; @@ -782,7 +782,7 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf, pfn = src / KPMSIZE; count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); if (src & KPMMASK || count & KPMMASK) - return -EIO; + return -EINVAL; while (count > 0) { ppage = NULL; -- cgit v1.2.3 From aab2545fdd6641b76af0ae96456c4ca9d1e50dad Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 6 Jun 2008 11:31:39 -0700 Subject: uml: activate_mm: remove the dead PF_BORROWED_MM check use_mm() was changed to use switch_mm() instead of activate_mm(), since then nobody calls (and nobody should call) activate_mm() with PF_BORROWED_MM bit set. As Jeff Dike pointed out, we can also remove the "old != new" check, it is always true. Signed-off-by: Oleg Nesterov Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/aio.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'fs') diff --git a/fs/aio.c b/fs/aio.c index b5253e77eb2..0fb3117ddd9 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -591,10 +591,6 @@ static void use_mm(struct mm_struct *mm) atomic_inc(&mm->mm_count); tsk->mm = mm; tsk->active_mm = mm; - /* - * Note that on UML this *requires* PF_BORROWED_MM to be set, otherwise - * it won't work. Update it accordingly if you change it here - */ switch_mm(active_mm, mm, tsk); task_unlock(tsk); -- cgit v1.2.3 From dbdbb87636e882042cbe53d5d4eac94206f8db83 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 10 Jun 2008 21:21:56 +0000 Subject: [CIFS] Fix hang in mount when negprot causes server to kill tcp session Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/CHANGES | 5 +++++ fs/cifs/connect.c | 1 + 2 files changed, 6 insertions(+) (limited to 'fs') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 28e3d5c5fca..1f3465201fd 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -2,6 +2,11 @@ Version 1.53 ------------ DFS support added (Microsoft Distributed File System client support needed for referrals which enable a hierarchical name space among servers). +Disable temporary caching of mode bits to servers which do not support +storing of mode (e.g. Windows servers, when client mounts without cifsacl +mount option) and add new "dynperm" mount option to enable temporary caching +of mode (enable old behavior). Fix hang on mount caused when server crashes +tcp session during negotiate protocol. Version 1.52 ------------ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d49e274f8eb..e8fa46c7cff 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -653,6 +653,7 @@ multi_t2_fnd: spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; spin_unlock(&GlobalMid_Lock); + wake_up_all(&server->response_q); /* don't exit until kthread_stop is called */ set_current_state(TASK_UNINTERRUPTIBLE); -- cgit v1.2.3 From 79ee9a8b2d328243488fee8b55bfacc822049a2a Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 10 Jun 2008 21:37:02 +0000 Subject: [CIFS] cifs: fix oops on mount when CONFIG_CIFS_DFS_UPCALL is enabled simple "mount -t cifs //xxx /mnt" oopsed on strlen of options http://kerneloops.org/guilty.php?guilty=cifs_get_sb&version=2.6.25-release&start=16711 \ 68&end=1703935&class=oops Signed-off-by: Marcin Slusarz Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5df93fd6303..86b4d5f405a 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -97,9 +97,6 @@ cifs_read_super(struct super_block *sb, void *data, { struct inode *inode; struct cifs_sb_info *cifs_sb; -#ifdef CONFIG_CIFS_DFS_UPCALL - int len; -#endif int rc = 0; /* BB should we make this contingent on mount parm? */ @@ -117,15 +114,17 @@ cifs_read_super(struct super_block *sb, void *data, * complex operation (mount), and in case of fail * just exit instead of doing mount and attempting * undo it if this copy fails?*/ - len = strlen(data); - cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL); - if (cifs_sb->mountdata == NULL) { - kfree(sb->s_fs_info); - sb->s_fs_info = NULL; - return -ENOMEM; + if (data) { + int len = strlen(data); + cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL); + if (cifs_sb->mountdata == NULL) { + kfree(sb->s_fs_info); + sb->s_fs_info = NULL; + return -ENOMEM; + } + strncpy(cifs_sb->mountdata, data, len + 1); + cifs_sb->mountdata[len] = '\0'; } - strncpy(cifs_sb->mountdata, data, len + 1); - cifs_sb->mountdata[len] = '\0'; #endif rc = cifs_mount(sb, cifs_sb, data, devname); -- cgit v1.2.3 From 2d518f84e5ecd1d71df0e6ac5176d212f68c27ce Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Thu, 12 Jun 2008 15:21:28 -0700 Subject: fat: relax the permission check of fat_setattr() New chmod() allows only acceptable permission, and if not acceptable, it returns -EPERM. Old one allows even if it can't store permission to on disk inode. But it seems too strict for users. E.g. https://bugzilla.redhat.com/show_bug.cgi?id=449080: With new one, rsync couldn't create the temporary file. So, this patch allows like old one, but now it doesn't change the permission if it can't store, and it returns 0. Also, this patch fixes missing check. Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/file.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/fat/file.c b/fs/fat/file.c index 27cc1164ec3..771326b8047 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -257,26 +257,34 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) } EXPORT_SYMBOL_GPL(fat_getattr); -static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode, - mode_t mode) +static int fat_sanitize_mode(const struct msdos_sb_info *sbi, + struct inode *inode, umode_t *mode_ptr) { - mode_t mask, req = mode & ~S_IFMT; + mode_t mask, perm; - if (S_ISREG(mode)) + /* + * Note, the basic check is already done by a caller of + * (attr->ia_mode & ~MSDOS_VALID_MODE) + */ + + if (S_ISREG(inode->i_mode)) mask = sbi->options.fs_fmask; else mask = sbi->options.fs_dmask; + perm = *mode_ptr & ~(S_IFMT | mask); + /* * Of the r and x bits, all (subject to umask) must be present. Of the * w bits, either all (subject to umask) or none must be present. */ - req &= ~mask; - if ((req & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) + if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) return -EPERM; - if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask))) + if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) return -EPERM; + *mode_ptr &= S_IFMT | perm; + return 0; } @@ -299,7 +307,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) { struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); struct inode *inode = dentry->d_inode; - int mask, error = 0; + int error = 0; unsigned int ia_valid; lock_kernel(); @@ -332,12 +340,13 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) error = 0; goto out; } + if (((attr->ia_valid & ATTR_UID) && (attr->ia_uid != sbi->options.fs_uid)) || ((attr->ia_valid & ATTR_GID) && (attr->ia_gid != sbi->options.fs_gid)) || ((attr->ia_valid & ATTR_MODE) && - fat_check_mode(sbi, inode, attr->ia_mode) < 0)) + (attr->ia_mode & ~MSDOS_VALID_MODE))) error = -EPERM; if (error) { @@ -346,15 +355,16 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) goto out; } - error = inode_setattr(inode, attr); - if (error) - goto out; + /* + * We don't return -EPERM here. Yes, strange, but this is too + * old behavior. + */ + if (attr->ia_valid & ATTR_MODE) { + if (fat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) + attr->ia_valid &= ~ATTR_MODE; + } - if (S_ISDIR(inode->i_mode)) - mask = sbi->options.fs_dmask; - else - mask = sbi->options.fs_fmask; - inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask); + error = inode_setattr(inode, attr); out: unlock_kernel(); return error; -- cgit v1.2.3 From 2165009bdf63f79716a36ad545df14c3cdf958b7 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 12 Jun 2008 15:21:47 -0700 Subject: pagemap: pass mm into pagewalkers We need this at least for huge page detection for now, because powerpc needs the vm_area_struct to be able to determine whether a virtual address is referring to a huge page (its pmd_huge() doesn't work). It might also come in handy for some of the other users. Signed-off-by: Dave Hansen Acked-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'fs') diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 17403629e33..f0df3109343 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -315,9 +315,9 @@ struct mem_size_stats { }; static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, - void *private) + struct mm_walk *walk) { - struct mem_size_stats *mss = private; + struct mem_size_stats *mss = walk->private; struct vm_area_struct *vma = mss->vma; pte_t *pte, ptent; spinlock_t *ptl; @@ -365,19 +365,21 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, return 0; } -static struct mm_walk smaps_walk = { .pmd_entry = smaps_pte_range }; - static int show_smap(struct seq_file *m, void *v) { struct vm_area_struct *vma = v; struct mem_size_stats mss; int ret; + struct mm_walk smaps_walk = { + .pmd_entry = smaps_pte_range, + .mm = vma->vm_mm, + .private = &mss, + }; memset(&mss, 0, sizeof mss); mss.vma = vma; if (vma->vm_mm && !is_vm_hugetlb_page(vma)) - walk_page_range(vma->vm_mm, vma->vm_start, vma->vm_end, - &smaps_walk, &mss); + walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); ret = show_map(m, v); if (ret) @@ -426,9 +428,9 @@ const struct file_operations proc_smaps_operations = { }; static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, - unsigned long end, void *private) + unsigned long end, struct mm_walk *walk) { - struct vm_area_struct *vma = private; + struct vm_area_struct *vma = walk->private; pte_t *pte, ptent; spinlock_t *ptl; struct page *page; @@ -452,8 +454,6 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, return 0; } -static struct mm_walk clear_refs_walk = { .pmd_entry = clear_refs_pte_range }; - static ssize_t clear_refs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -476,11 +476,17 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf, return -ESRCH; mm = get_task_mm(task); if (mm) { + static struct mm_walk clear_refs_walk; + memset(&clear_refs_walk, 0, sizeof(clear_refs_walk)); + clear_refs_walk.pmd_entry = clear_refs_pte_range; + clear_refs_walk.mm = mm; down_read(&mm->mmap_sem); - for (vma = mm->mmap; vma; vma = vma->vm_next) + for (vma = mm->mmap; vma; vma = vma->vm_next) { + clear_refs_walk.private = vma; if (!is_vm_hugetlb_page(vma)) - walk_page_range(mm, vma->vm_start, vma->vm_end, - &clear_refs_walk, vma); + walk_page_range(vma->vm_start, vma->vm_end, + &clear_refs_walk); + } flush_tlb_mm(mm); up_read(&mm->mmap_sem); mmput(mm); @@ -528,9 +534,9 @@ static int add_to_pagemap(unsigned long addr, u64 pfn, } static int pagemap_pte_hole(unsigned long start, unsigned long end, - void *private) + struct mm_walk *walk) { - struct pagemapread *pm = private; + struct pagemapread *pm = walk->private; unsigned long addr; int err = 0; for (addr = start; addr < end; addr += PAGE_SIZE) { @@ -548,9 +554,9 @@ static u64 swap_pte_to_pagemap_entry(pte_t pte) } static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, - void *private) + struct mm_walk *walk) { - struct pagemapread *pm = private; + struct pagemapread *pm = walk->private; pte_t *pte; int err = 0; @@ -675,8 +681,8 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, * user buffer is tracked in "pm", and the walk * will stop when we hit the end of the buffer. */ - ret = walk_page_range(mm, start_vaddr, end_vaddr, - &pagemap_walk, &pm); + ret = walk_page_range(start_vaddr, end_vaddr, + &pagemap_walk); if (ret == PM_END_OF_BUFFER) ret = 0; /* don't need mmap_sem for these, but this looks cleaner */ -- cgit v1.2.3 From bcf8039ed45f56013c4afea5520bca7d909e5e61 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 12 Jun 2008 15:21:48 -0700 Subject: pagemap: fix large pages in pagemap We were walking right into huge page areas in the pagemap walker, and calling the pmds pmd_bad() and clearing them. That leaked huge pages. Bad. This patch at least works around that for now. It ignores huge pages in the pagemap walker for the time being, and won't leak those pages. Signed-off-by: Dave Hansen Acked-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index f0df3109343..ab8ccc9d14f 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -553,24 +553,45 @@ static u64 swap_pte_to_pagemap_entry(pte_t pte) return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT); } +static unsigned long pte_to_pagemap_entry(pte_t pte) +{ + unsigned long pme = 0; + if (is_swap_pte(pte)) + pme = PM_PFRAME(swap_pte_to_pagemap_entry(pte)) + | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP; + else if (pte_present(pte)) + pme = PM_PFRAME(pte_pfn(pte)) + | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT; + return pme; +} + static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, struct mm_walk *walk) { + struct vm_area_struct *vma; struct pagemapread *pm = walk->private; pte_t *pte; int err = 0; + /* find the first VMA at or above 'addr' */ + vma = find_vma(walk->mm, addr); for (; addr != end; addr += PAGE_SIZE) { u64 pfn = PM_NOT_PRESENT; - pte = pte_offset_map(pmd, addr); - if (is_swap_pte(*pte)) - pfn = PM_PFRAME(swap_pte_to_pagemap_entry(*pte)) - | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP; - else if (pte_present(*pte)) - pfn = PM_PFRAME(pte_pfn(*pte)) - | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT; - /* unmap so we're not in atomic when we copy to userspace */ - pte_unmap(pte); + + /* check to see if we've left 'vma' behind + * and need a new, higher one */ + if (vma && (addr >= vma->vm_end)) + vma = find_vma(walk->mm, addr); + + /* check that 'vma' actually covers this address, + * and that it isn't a huge page vma */ + if (vma && (vma->vm_start <= addr) && + !is_vm_hugetlb_page(vma)) { + pte = pte_offset_map(pmd, addr); + pfn = pte_to_pagemap_entry(*pte); + /* unmap before userspace copy */ + pte_unmap(pte); + } err = add_to_pagemap(addr, pfn, pm); if (err) return err; -- cgit v1.2.3