diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/aio.c | 8 | ||||
-rw-r--r-- | fs/bio.c | 2 | ||||
-rw-r--r-- | fs/buffer.c | 4 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 18 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 25 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 9 | ||||
-rw-r--r-- | fs/cifs/dir.c | 5 | ||||
-rw-r--r-- | fs/cifs/dns_resolve.c | 8 | ||||
-rw-r--r-- | fs/cifs/file.c | 4 | ||||
-rw-r--r-- | fs/cifs/inode.c | 161 | ||||
-rw-r--r-- | fs/cifs/link.c | 2 | ||||
-rw-r--r-- | fs/dquot.c | 2 | ||||
-rw-r--r-- | fs/ecryptfs/dentry.c | 2 | ||||
-rw-r--r-- | fs/ext3/acl.c | 8 | ||||
-rw-r--r-- | fs/ext3/resize.c | 4 | ||||
-rw-r--r-- | fs/ext3/xattr.c | 4 | ||||
-rw-r--r-- | fs/fs-writeback.c | 6 | ||||
-rw-r--r-- | fs/hfs/brec.c | 18 | ||||
-rw-r--r-- | fs/isofs/compress.c | 11 | ||||
-rw-r--r-- | fs/jbd/journal.c | 5 | ||||
-rw-r--r-- | fs/jbd/recovery.c | 2 | ||||
-rw-r--r-- | fs/jbd/transaction.c | 8 | ||||
-rw-r--r-- | fs/jbd2/recovery.c | 2 | ||||
-rw-r--r-- | fs/locks.c | 4 | ||||
-rw-r--r-- | fs/namei.c | 6 | ||||
-rw-r--r-- | fs/nfs/read.c | 5 | ||||
-rw-r--r-- | fs/nfs/super.c | 2 | ||||
-rw-r--r-- | fs/nfs/write.c | 8 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 4 | ||||
-rw-r--r-- | fs/proc/base.c | 24 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 68 | ||||
-rw-r--r-- | fs/romfs/inode.c | 30 | ||||
-rw-r--r-- | fs/super.c | 6 | ||||
-rw-r--r-- | fs/sysfs/file.c | 8 | ||||
-rw-r--r-- | fs/ufs/balloc.c | 4 |
35 files changed, 302 insertions, 185 deletions
@@ -996,6 +996,14 @@ put_rq: /* everything turned out well, dispose of the aiocb. */ ret = __aio_put_req(ctx, iocb); + /* + * We have to order our ring_info tail store above and test + * of the wait list below outside the wait lock. This is + * like in wake_up_bit() where clearing a bit has to be + * ordered with the unlocked test. + */ + smp_mb(); + if (waitqueue_active(&ctx->wait)) wake_up(&ctx->wait); @@ -1194,6 +1194,8 @@ EXPORT_SYMBOL(bio_hw_segments); EXPORT_SYMBOL(bio_add_page); EXPORT_SYMBOL(bio_add_pc_page); EXPORT_SYMBOL(bio_get_nr_vecs); +EXPORT_SYMBOL(bio_map_user); +EXPORT_SYMBOL(bio_unmap_user); EXPORT_SYMBOL(bio_map_kern); EXPORT_SYMBOL(bio_pair_release); EXPORT_SYMBOL(bio_split); diff --git a/fs/buffer.c b/fs/buffer.c index ddfdd2c80bf..7ba58386bee 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -3213,7 +3213,7 @@ static int buffer_cpu_notify(struct notifier_block *self, } /** - * bh_uptodate_or_lock: Test whether the buffer is uptodate + * bh_uptodate_or_lock - Test whether the buffer is uptodate * @bh: struct buffer_head * * Return true if the buffer is up-to-date and false, @@ -3232,7 +3232,7 @@ int bh_uptodate_or_lock(struct buffer_head *bh) EXPORT_SYMBOL(bh_uptodate_or_lock); /** - * bh_submit_read: Submit a locked buffer for reading + * bh_submit_read - Submit a locked buffer for reading * @bh: struct buffer_head * * Returns zero on success and -EIO on error. diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 7f883825341..a1a95b02713 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -74,7 +74,7 @@ static char *cifs_get_share_name(const char *node_name) pSep = memchr(UNC+2, '\\', len-2); if (!pSep) { cERROR(1, ("%s: no server name end in node name: %s", - __FUNCTION__, node_name)); + __func__, node_name)); kfree(UNC); return NULL; } @@ -84,7 +84,7 @@ static char *cifs_get_share_name(const char *node_name) pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC)); if (!pSep) { cERROR(1, ("%s:2 cant find share name in node name: %s", - __FUNCTION__, node_name)); + __func__, node_name)); kfree(UNC); return NULL; } @@ -127,7 +127,7 @@ static char *compose_mount_options(const char *sb_mountdata, rc = dns_resolve_server_name_to_ip(*devname, &srvIP); if (rc != 0) { cERROR(1, ("%s: Failed to resolve server part of %s to IP", - __FUNCTION__, *devname)); + __func__, *devname)); mountdata = ERR_PTR(rc); goto compose_mount_options_out; } @@ -181,8 +181,8 @@ static char *compose_mount_options(const char *sb_mountdata, } } - /*cFYI(1,("%s: parent mountdata: %s", __FUNCTION__,sb_mountdata));*/ - /*cFYI(1, ("%s: submount mountdata: %s", __FUNCTION__, mountdata ));*/ + /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/ + /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/ compose_mount_options_out: kfree(srvIP); @@ -302,7 +302,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) int rc = 0; struct vfsmount *mnt = ERR_PTR(-ENOENT); - cFYI(1, ("in %s", __FUNCTION__)); + cFYI(1, ("in %s", __func__)); BUG_ON(IS_ROOT(dentry)); xid = GetXid(); @@ -336,7 +336,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) len = strlen(referrals[i].node_name); if (len < 2) { cERROR(1, ("%s: Net Address path too short: %s", - __FUNCTION__, referrals[i].node_name)); + __func__, referrals[i].node_name)); rc = -EINVAL; goto out_err; } @@ -344,7 +344,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) nd->path.dentry, referrals[i].node_name); cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", - __FUNCTION__, + __func__, referrals[i].node_name, mnt)); /* complete mount procedure if we accured submount */ @@ -365,7 +365,7 @@ out: FreeXid(xid); free_dfs_info_array(referrals, num_referrals); kfree(full_path); - cFYI(1, ("leaving %s" , __FUNCTION__)); + cFYI(1, ("leaving %s" , __func__)); return ERR_PTR(rc); out_err: path_put(&nd->path); diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index f93932c2177..1f5a4289b84 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -1,7 +1,7 @@ /* * fs/cifs/cifsacl.c * - * Copyright (C) International Business Machines Corp., 2007 + * Copyright (C) International Business Machines Corp., 2007,2008 * Author(s): Steve French (sfrench@us.ibm.com) * * Contains the routines for mapping CIFS/NTFS ACLs @@ -556,9 +556,9 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, /* Retrieve an ACL from the server */ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, - const char *path) + const char *path, const __u16 *pfid) { - struct cifsFileInfo *open_file; + struct cifsFileInfo *open_file = NULL; int unlock_file = FALSE; int xid; int rc = -EIO; @@ -573,7 +573,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, return NULL; xid = GetXid(); - open_file = find_readable_file(CIFS_I(inode)); + if (pfid == NULL) + open_file = find_readable_file(CIFS_I(inode)); + else + fid = *pfid; + sb = inode->i_sb; if (sb == NULL) { FreeXid(xid); @@ -584,7 +588,7 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, if (open_file) { unlock_file = TRUE; fid = open_file->netfid; - } else { + } else if (pfid == NULL) { int oplock = FALSE; /* open file */ rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, @@ -600,10 +604,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen)); - if (unlock_file == TRUE) + if (unlock_file == TRUE) /* find_readable_file increments ref count */ atomic_dec(&open_file->wrtPending); - else + else if (pfid == NULL) /* if opened above we have to close the handle */ CIFSSMBClose(xid, cifs_sb->tcon, fid); + /* else handle was passed in by caller */ FreeXid(xid); return pntsd; @@ -664,14 +669,14 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, } /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ -void acl_to_uid_mode(struct inode *inode, const char *path) +void acl_to_uid_mode(struct inode *inode, const char *path, const __u16 *pfid) { struct cifs_ntsd *pntsd = NULL; u32 acllen = 0; int rc = 0; cFYI(DBG2, ("converting ACL to mode for %s", path)); - pntsd = get_cifs_acl(&acllen, inode, path); + pntsd = get_cifs_acl(&acllen, inode, path, pfid); /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ if (pntsd) @@ -694,7 +699,7 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) cFYI(DBG2, ("set ACL from mode for %s", path)); /* Get the security descriptor */ - pntsd = get_cifs_acl(&acllen, inode, path); + pntsd = get_cifs_acl(&acllen, inode, path, NULL); /* Add three ACEs for owner, group, everyone getting rid of other ACEs as chmod disables ACEs and set the security descriptor */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0af63e6b426..7e5e0e78cd7 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -39,8 +39,8 @@ extern int smb_send(struct socket *, struct smb_hdr *, unsigned int /* length */ , struct sockaddr *); extern unsigned int _GetXid(void); extern void _FreeXid(unsigned int); -#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid)); -#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));} +#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid)); +#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));} extern char *build_path_from_dentry(struct dentry *); extern char *build_wildcard_path_from_dentry(struct dentry *direntry); /* extern void renew_parental_timestamps(struct dentry *direntry);*/ @@ -92,11 +92,12 @@ 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, - struct super_block *sb, int xid); + struct super_block *sb, int xid, const __u16 *pfid); extern int cifs_get_inode_info_unix(struct inode **pinode, const unsigned char *search_path, struct super_block *sb, int xid); -extern void acl_to_uid_mode(struct inode *inode, const char *search_path); +extern void acl_to_uid_mode(struct inode *inode, const char *path, + const __u16 *pfid); extern int mode_to_acl(struct inode *inode, const char *path, __u64); extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 4e83b47c4b3..0f5c62ba403 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -229,7 +229,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, inode->i_sb, xid); else { rc = cifs_get_inode_info(&newinode, full_path, - buf, inode->i_sb, xid); + buf, inode->i_sb, xid, + &fileHandle); if (newinode) { newinode->i_mode = mode; if ((oplock & CIFS_CREATE_ACTION) && @@ -483,7 +484,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, parent_dir_inode->i_sb, xid); else rc = cifs_get_inode_info(&newInode, full_path, NULL, - parent_dir_inode->i_sb, xid); + parent_dir_inode->i_sb, xid, NULL); if ((rc == 0) && (newInode != NULL)) { if (pTcon->nocase) diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index ef7f4382434..7cc86c41818 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c @@ -77,14 +77,14 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) /* search for server name delimiter */ len = strlen(unc); if (len < 3) { - cFYI(1, ("%s: unc is too short: %s", __FUNCTION__, unc)); + cFYI(1, ("%s: unc is too short: %s", __func__, unc)); return -EINVAL; } len -= 2; name = memchr(unc+2, '\\', len); if (!name) { cFYI(1, ("%s: probably server name is whole unc: %s", - __FUNCTION__, unc)); + __func__, unc)); } else { len = (name - unc) - 2/* leading // */; } @@ -104,7 +104,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) if (*ip_addr) { memcpy(*ip_addr, rkey->payload.data, len); (*ip_addr)[len] = '\0'; - cFYI(1, ("%s: resolved: %s to %s", __FUNCTION__, + cFYI(1, ("%s: resolved: %s to %s", __func__, rkey->description, *ip_addr )); @@ -114,7 +114,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) } key_put(rkey); } else { - cERROR(1, ("%s: unable to resolve: %s", __FUNCTION__, name)); + cERROR(1, ("%s: unable to resolve: %s", __func__, name)); } kfree(name); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index fa849c91d32..40b690073fc 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -145,7 +145,7 @@ client_can_cache: full_path, inode->i_sb, xid); else rc = cifs_get_inode_info(&file->f_path.dentry->d_inode, - full_path, buf, inode->i_sb, xid); + full_path, buf, inode->i_sb, xid, NULL); if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { pCifsInode->clientCanCacheAll = TRUE; @@ -440,7 +440,7 @@ reopen_error_exit: else rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb, - xid); + xid, NULL); } /* else we are writing out data to server already and could deadlock if we tried to flush data, and since we do not know if we have data that would diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 24eb4d39215..bc673c8c1e6 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -30,7 +30,7 @@ #include "cifs_fs_sb.h" -static void cifs_set_ops(struct inode *inode) +static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); @@ -57,8 +57,16 @@ static void cifs_set_ops(struct inode *inode) inode->i_data.a_ops = &cifs_addr_ops; break; case S_IFDIR: - inode->i_op = &cifs_dir_inode_ops; - inode->i_fop = &cifs_dir_ops; +#ifdef CONFIG_CIFS_DFS_UPCALL + if (is_dfs_referral) { + inode->i_op = &cifs_dfs_referral_inode_operations; + } else { +#else /* NO DFS support, treat as a directory */ + { +#endif + inode->i_op = &cifs_dir_inode_ops; + inode->i_fop = &cifs_dir_ops; + } break; case S_IFLNK: inode->i_op = &cifs_symlink_inode_ops; @@ -153,6 +161,30 @@ static void cifs_unix_info_to_inode(struct inode *inode, spin_unlock(&inode->i_lock); } +static const unsigned char *cifs_get_search_path(struct cifsTconInfo *pTcon, + const char *search_path) +{ + int tree_len; + int path_len; + char *tmp_path; + + 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); + 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) { @@ -161,41 +193,31 @@ int cifs_get_inode_info_unix(struct inode **pinode, struct cifsTconInfo *pTcon; struct inode *inode; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - char *tmp_path; + 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(pTcon, search_path); + +try_again_CIFSSMBUnixQPathInfo: /* could have done a find first instead but this returns more info */ - rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, + rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData, 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) { - tmp_path = - kmalloc(strnlen(pTcon->treeName, - MAX_TREE_SIZE + 1) + - strnlen(search_path, MAX_PATHCONF) + 1, - GFP_KERNEL); - if (tmp_path == NULL) - return -ENOMEM; - - /* have to skip first of the double backslash of - UNC name */ - strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); - strncat(tmp_path, search_path, MAX_PATHCONF); - rc = connect_to_dfs_path(xid, pTcon->ses, - /* treename + */ tmp_path, - cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - kfree(tmp_path); - - /* BB fix up inode etc. */ - } else if (rc) { - return 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; } else { struct cifsInodeInfo *cifsInfo; __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes); @@ -204,8 +226,10 @@ int cifs_get_inode_info_unix(struct inode **pinode, /* get new inode */ if (*pinode == NULL) { *pinode = new_inode(sb); - if (*pinode == NULL) - return -ENOMEM; + 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? */ @@ -237,8 +261,11 @@ int cifs_get_inode_info_unix(struct inode **pinode, (unsigned long) inode->i_size, (unsigned long long)inode->i_blocks)); - cifs_set_ops(inode); + cifs_set_ops(inode, is_dfs_referral); } +cgiiu_exit: + if (full_path != search_path) + kfree(full_path); return rc; } @@ -347,15 +374,16 @@ 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, - struct super_block *sb, int xid) + 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); - char *tmp_path; + const unsigned char *full_path = NULL; char *buf = NULL; int adjustTZ = FALSE; + bool is_dfs_referral = false; pTcon = cifs_sb->tcon; cFYI(1, ("Getting info on %s", search_path)); @@ -373,8 +401,12 @@ int cifs_get_inode_info(struct inode **pinode, if (buf == NULL) return -ENOMEM; pfindData = (FILE_ALL_INFO *)buf; + + full_path = cifs_get_search_path(pTcon, search_path); + +try_again_CIFSSMBQPathInfo: /* could do find first instead but this returns more info */ - rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, + rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, 0 /* not legacy */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -382,7 +414,7 @@ int cifs_get_inode_info(struct inode **pinode, when server claims no NT SMB support and the above call failed at least once - set flag in tcon or mount */ if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { - rc = SMBQueryInformation(xid, pTcon, search_path, + rc = SMBQueryInformation(xid, pTcon, full_path, pfindData, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -391,31 +423,15 @@ int cifs_get_inode_info(struct inode **pinode, } /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ if (rc) { - if (rc == -EREMOTE) { - tmp_path = - kmalloc(strnlen - (pTcon->treeName, - MAX_TREE_SIZE + 1) + - strnlen(search_path, MAX_PATHCONF) + 1, - GFP_KERNEL); - if (tmp_path == NULL) { - kfree(buf); - return -ENOMEM; + if (rc == -EREMOTE && !is_dfs_referral) { + is_dfs_referral = true; + if (full_path != search_path) { + kfree(full_path); + full_path = search_path; } - - strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); - strncat(tmp_path, search_path, MAX_PATHCONF); - rc = connect_to_dfs_path(xid, pTcon->ses, - /* treename + */ tmp_path, - cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - kfree(tmp_path); - /* BB fix up inode etc. */ - } else if (rc) { - kfree(buf); - return rc; + goto try_again_CIFSSMBQPathInfo; } + goto cgii_exit; } else { struct cifsInodeInfo *cifsInfo; __u32 attr = le32_to_cpu(pfindData->Attributes); @@ -424,8 +440,8 @@ int cifs_get_inode_info(struct inode **pinode, if (*pinode == NULL) { *pinode = new_inode(sb); if (*pinode == NULL) { - kfree(buf); - return -ENOMEM; + 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 @@ -559,7 +575,7 @@ int cifs_get_inode_info(struct inode **pinode, /* 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); + acl_to_uid_mode(inode, search_path, pfid); } #endif if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { @@ -573,8 +589,11 @@ int cifs_get_inode_info(struct inode **pinode, atomic_set(&cifsInfo->inUse, 1); } - cifs_set_ops(inode); + cifs_set_ops(inode, is_dfs_referral); } +cgii_exit: + if (full_path != search_path) + kfree(full_path); kfree(buf); return rc; } @@ -603,7 +622,8 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) if (cifs_sb->tcon->unix_ext) rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); else - rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); + rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid, + NULL); if (rc && cifs_sb->tcon->ipc) { cFYI(1, ("ipc connection - fake read inode")); inode->i_mode |= S_IFDIR; @@ -804,7 +824,7 @@ static void posix_fill_in_inode(struct inode *tmp_inode, local_size = tmp_inode->i_size; cifs_unix_info_to_inode(tmp_inode, pData, 1); - cifs_set_ops(tmp_inode); + cifs_set_ops(tmp_inode, false); if (!S_ISREG(tmp_inode->i_mode)) return; @@ -936,7 +956,7 @@ mkdir_get_info: inode->i_sb, xid); else rc = cifs_get_inode_info(&newinode, full_path, NULL, - inode->i_sb, xid); + inode->i_sb, xid, NULL); if (pTcon->nocase) direntry->d_op = &cifs_ci_dentry_ops; @@ -1218,7 +1238,7 @@ int cifs_revalidate(struct dentry *direntry) } } else { rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, - direntry->d_sb, xid); + direntry->d_sb, xid, NULL); if (rc) { cFYI(1, ("error on getting revalidate info %d", rc)); /* if (rc != -ENOENT) @@ -1407,11 +1427,10 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) } cifsInode = CIFS_I(direntry->d_inode); - /* BB check if we need to refresh inode from server now ? BB */ - - if (attrs->ia_valid & ATTR_SIZE) { + if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { /* - Flush data before changing file size on server. If the + Flush data before changing file size or changing the last + write time of the file on the server. If the flush returns error, store it to report later and continue. BB: This should be smarter. Why bother flushing pages that will be truncated anyway? Also, should we error out here if @@ -1422,7 +1441,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) CIFS_I(direntry->d_inode)->write_behind_rc = rc; rc = 0; } + } + if (attrs->ia_valid & ATTR_SIZE) { /* To avoid spurious oplock breaks from server, in the case of inodes that we already have open, avoid doing path based setting of file size if we can do it by handle. diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 1d6fb01b8e6..d4e7ec93285 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -205,7 +205,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) inode->i_sb, xid); else rc = cifs_get_inode_info(&newinode, full_path, NULL, - inode->i_sb, xid); + inode->i_sb, xid, NULL); if (rc != 0) { cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d", diff --git a/fs/dquot.c b/fs/dquot.c index 9c7feb62eed..41b9dbd68b0 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -1522,8 +1522,8 @@ int vfs_quota_off(struct super_block *sb, int type) truncate_inode_pages(&toputinode[cnt]->i_data, 0); mutex_unlock(&toputinode[cnt]->i_mutex); mark_inode_dirty(toputinode[cnt]); - iput(toputinode[cnt]); } + iput(toputinode[cnt]); mutex_unlock(&dqopt->dqonoff_mutex); } if (sb->s_bdev) diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c index 841a032050a..5e596583946 100644 --- a/fs/ecryptfs/dentry.c +++ b/fs/ecryptfs/dentry.c @@ -80,8 +80,8 @@ static void ecryptfs_d_release(struct dentry *dentry) { if (ecryptfs_dentry_to_private(dentry)) { if (ecryptfs_dentry_to_lower(dentry)) { - mntput(ecryptfs_dentry_to_lower_mnt(dentry)); dput(ecryptfs_dentry_to_lower(dentry)); + mntput(ecryptfs_dentry_to_lower_mnt(dentry)); } kmem_cache_free(ecryptfs_dentry_info_cache, ecryptfs_dentry_to_private(dentry)); diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index d34e9967430..a754d184817 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -37,7 +37,7 @@ ext3_acl_from_disk(const void *value, size_t size) return ERR_PTR(-EINVAL); if (count == 0) return NULL; - acl = posix_acl_alloc(count, GFP_KERNEL); + acl = posix_acl_alloc(count, GFP_NOFS); if (!acl) return ERR_PTR(-ENOMEM); for (n=0; n < count; n++) { @@ -91,7 +91,7 @@ ext3_acl_to_disk(const struct posix_acl *acl, size_t *size) *size = ext3_acl_size(acl->a_count); ext_acl = kmalloc(sizeof(ext3_acl_header) + acl->a_count * - sizeof(ext3_acl_entry), GFP_KERNEL); + sizeof(ext3_acl_entry), GFP_NOFS); if (!ext_acl) return ERR_PTR(-ENOMEM); ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION); @@ -187,7 +187,7 @@ ext3_get_acl(struct inode *inode, int type) } retval = ext3_xattr_get(inode, name_index, "", NULL, 0); if (retval > 0) { - value = kmalloc(retval, GFP_KERNEL); + value = kmalloc(retval, GFP_NOFS); if (!value) return ERR_PTR(-ENOMEM); retval = ext3_xattr_get(inode, name_index, "", value, retval); @@ -335,7 +335,7 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) if (error) goto cleanup; } - clone = posix_acl_clone(acl, GFP_KERNEL); + clone = posix_acl_clone(acl, GFP_NOFS); error = -ENOMEM; if (!clone) goto cleanup; diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 9397d779c43..0e97b6e07cb 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -485,7 +485,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, goto exit_dindj; n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *), - GFP_KERNEL); + GFP_NOFS); if (!n_group_desc) { err = -ENOMEM; ext3_warning (sb, __FUNCTION__, @@ -568,7 +568,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, int res, i; int err; - primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_KERNEL); + primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_NOFS); if (!primary) return -ENOMEM; diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index fb89c299bec..a6ea4d6a8bb 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -728,7 +728,7 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, ce = NULL; } ea_bdebug(bs->bh, "cloning"); - s->base = kmalloc(bs->bh->b_size, GFP_KERNEL); + s->base = kmalloc(bs->bh->b_size, GFP_NOFS); error = -ENOMEM; if (s->base == NULL) goto cleanup; @@ -740,7 +740,7 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, } } else { /* Allocate a buffer where we construct the new block. */ - s->base = kzalloc(sb->s_blocksize, GFP_KERNEL); + s->base = kzalloc(sb->s_blocksize, GFP_NOFS); /* assert(header == s->base) */ error = -ENOMEM; if (s->base == NULL) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index c0076077d33..06557679ca4 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -751,7 +751,7 @@ int generic_osync_inode(struct inode *inode, struct address_space *mapping, int EXPORT_SYMBOL(generic_osync_inode); /** - * writeback_acquire: attempt to get exclusive writeback access to a device + * writeback_acquire - attempt to get exclusive writeback access to a device * @bdi: the device's backing_dev_info structure * * It is a waste of resources to have more than one pdflush thread blocked on @@ -768,7 +768,7 @@ int writeback_acquire(struct backing_dev_info *bdi) } /** - * writeback_in_progress: determine whether there is writeback in progress + * writeback_in_progress - determine whether there is writeback in progress * @bdi: the device's backing_dev_info structure. * * Determine whether there is writeback in progress against a backing device. @@ -779,7 +779,7 @@ int writeback_in_progress(struct backing_dev_info *bdi) } /** - * writeback_release: relinquish exclusive writeback access against a device. + * writeback_release - relinquish exclusive writeback access against a device. * @bdi: the device's backing_dev_info structure */ void writeback_release(struct backing_dev_info *bdi) diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c index 878bf25dbc6..92fb358ce82 100644 --- a/fs/hfs/brec.c +++ b/fs/hfs/brec.c @@ -229,7 +229,7 @@ skip: static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) { struct hfs_btree *tree; - struct hfs_bnode *node, *new_node; + struct hfs_bnode *node, *new_node, *next_node; struct hfs_bnode_desc node_desc; int num_recs, new_rec_off, new_off, old_rec_off; int data_start, data_end, size; @@ -248,6 +248,17 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) new_node->type = node->type; new_node->height = node->height; + if (node->next) + next_node = hfs_bnode_find(tree, node->next); + else + next_node = NULL; + + if (IS_ERR(next_node)) { + hfs_bnode_put(node); + hfs_bnode_put(new_node); + return next_node; + } + size = tree->node_size / 2 - node->num_recs * 2 - 14; old_rec_off = tree->node_size - 4; num_recs = 1; @@ -261,6 +272,8 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) /* panic? */ hfs_bnode_put(node); hfs_bnode_put(new_node); + if (next_node) + hfs_bnode_put(next_node); return ERR_PTR(-ENOSPC); } @@ -315,8 +328,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc)); /* update next bnode header */ - if (new_node->next) { - struct hfs_bnode *next_node = hfs_bnode_find(tree, new_node->next); + if (next_node) { next_node->prev = new_node->this; hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc)); node_desc.prev = cpu_to_be32(next_node->prev); diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c index 37dbd640478..defb932eee9 100644 --- a/fs/isofs/compress.c +++ b/fs/isofs/compress.c @@ -72,6 +72,17 @@ static int zisofs_readpage(struct file *file, struct page *page) offset = index & ~zisofs_block_page_mask; blockindex = offset >> zisofs_block_page_shift; maxpage = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + + /* + * If this page is wholly outside i_size we just return zero; + * do_generic_file_read() will handle this for us + */ + if (page->index >= maxpage) { + SetPageUptodate(page); + unlock_page(page); + return 0; + } + maxpage = min(zisofs_block_pages, maxpage-offset); for ( i = 0 ; i < maxpage ; i++, offset++ ) { diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 3943a8905eb..9816293442a 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -697,13 +697,14 @@ fail: */ /** - * journal_t * journal_init_dev() - creates an initialises a journal structure + * journal_t * journal_init_dev() - creates and initialises a journal structure * @bdev: Block device on which to create the journal * @fs_dev: Device which hold journalled filesystem for this journal. * @start: Block nr Start of journal. * @len: Length of the journal in blocks. * @blocksize: blocksize of journalling device - * @returns: a newly created journal_t * + * + * Returns: a newly created journal_t * * * journal_init_dev creates a journal which maps a fixed contiguous * range of blocks on an arbitrary block device. diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index 2b8edf4d6ea..43bc5e5ed06 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -478,7 +478,7 @@ static int do_one_pass(journal_t *journal, memcpy(nbh->b_data, obh->b_data, journal->j_blocksize); if (flags & JFS_FLAG_ESCAPE) { - *((__be32 *)bh->b_data) = + *((__be32 *)nbh->b_data) = cpu_to_be32(JFS_MAGIC_NUMBER); } diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index c6cbb6cd59b..2c9e8f5d13a 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1426,7 +1426,8 @@ int journal_stop(handle_t *handle) return err; } -/**int journal_force_commit() - force any uncommitted transactions +/** + * int journal_force_commit() - force any uncommitted transactions * @journal: journal to force * * For synchronous operations: force any uncommitted transactions @@ -1903,13 +1904,12 @@ zap_buffer_unlocked: } /** - * void journal_invalidatepage() - * @journal: journal to use for flush... + * void journal_invalidatepage() - invalidate a journal page + * @journal: journal to use for flush * @page: page to flush * @offset: length of page to invalidate. * * Reap page buffers containing data after offset in page. - * */ void journal_invalidatepage(journal_t *journal, struct page *page, diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 146411387ad..5d0405a9e7c 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -535,7 +535,7 @@ static int do_one_pass(journal_t *journal, memcpy(nbh->b_data, obh->b_data, journal->j_blocksize); if (flags & JBD2_FLAG_ESCAPE) { - *((__be32 *)bh->b_data) = + *((__be32 *)nbh->b_data) = cpu_to_be32(JBD2_MAGIC_NUMBER); } diff --git a/fs/locks.c b/fs/locks.c index f36f0e61558..d83fab1b77b 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1275,13 +1275,13 @@ out: EXPORT_SYMBOL(__break_lease); /** - * lease_get_mtime + * lease_get_mtime - get the last modified time of an inode * @inode: the inode * @time: pointer to a timespec which will contain the last modified time * * This is to force NFS clients to flush their caches for files with * exclusive leases. The justification is that if someone has an - * exclusive lease, then they could be modifiying it. + * exclusive lease, then they could be modifying it. */ void lease_get_mtime(struct inode *inode, struct timespec *time) { diff --git a/fs/namei.c b/fs/namei.c index 941c8e8228c..6b7a0eef409 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1364,13 +1364,13 @@ static int __lookup_one_len(const char *name, struct qstr *this, } /** - * lookup_one_len: filesystem helper to lookup single pathname component + * lookup_one_len - filesystem helper to lookup single pathname component * @name: pathname component to lookup * @base: base directory to lookup from * @len: maximum length @len should be interpreted to * - * Note that this routine is purely a helper for filesystem useage and should - * not be called by generic code. Also note that by using this function to + * Note that this routine is purely a helper for filesystem usage and should + * not be called by generic code. Also note that by using this function the * nameidata argument is passed to the filesystem methods and a filesystem * using this helper needs to be prepared for that. */ diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 3d7d9631e12..5a70be589bb 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -533,7 +533,10 @@ readpage_async_filler(void *data, struct page *page) if (len < PAGE_CACHE_SIZE) zero_user_segment(page, len, PAGE_CACHE_SIZE); - nfs_pageio_add_request(desc->pgio, new); + if (!nfs_pageio_add_request(desc->pgio, new)) { + error = desc->pgio->pg_error; + goto out_unlock; + } return 0; out_error: error = PTR_ERR(new); diff --git a/fs/nfs/super.c b/fs/nfs/super.c index fcf4b982c88..dd4dfcd632e 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -632,7 +632,7 @@ static int nfs_verify_server_address(struct sockaddr *addr) switch (addr->sa_family) { case AF_INET: { struct sockaddr_in *sa = (struct sockaddr_in *)addr; - return sa->sin_addr.s_addr != INADDR_ANY; + return sa->sin_addr.s_addr != htonl(INADDR_ANY); } case AF_INET6: { struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 80c61fdb272..bed63416a55 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -39,6 +39,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context*, unsigned int, unsigned int); static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc, struct inode *inode, int ioflags); +static void nfs_redirty_request(struct nfs_page *req); static const struct rpc_call_ops nfs_write_partial_ops; static const struct rpc_call_ops nfs_write_full_ops; static const struct rpc_call_ops nfs_commit_ops; @@ -288,7 +289,12 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, BUG(); } spin_unlock(&inode->i_lock); - nfs_pageio_add_request(pgio, req); + if (!nfs_pageio_add_request(pgio, req)) { + nfs_redirty_request(req); + nfs_end_page_writeback(page); + nfs_clear_page_tag_locked(req); + return pgio->pg_error; + } return 0; } diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 1eb771d79cc..3e6b3f41ee1 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -232,6 +232,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) fhp->fh_dentry = dentry; fhp->fh_export = exp; nfsd_nr_verified++; + cache_get(&exp->h); } else { /* * just rechecking permissions @@ -241,6 +242,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) dprintk("nfsd: fh_verify - just checking\n"); dentry = fhp->fh_dentry; exp = fhp->fh_export; + cache_get(&exp->h); /* * Set user creds for this exportpoint; necessary even * in the "just checking" case because this may be a @@ -252,8 +254,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) if (error) goto out; } - cache_get(&exp->h); - error = nfsd_mode_check(rqstp, dentry->d_inode->i_mode, type); if (error) diff --git a/fs/proc/base.c b/fs/proc/base.c index 9a4da0aae02..81d7d145292 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1036,6 +1036,26 @@ static const struct file_operations proc_loginuid_operations = { .read = proc_loginuid_read, .write = proc_loginuid_write, }; + +static ssize_t proc_sessionid_read(struct file * file, char __user * buf, + size_t count, loff_t *ppos) +{ + struct inode * inode = file->f_path.dentry->d_inode; + struct task_struct *task = get_proc_task(inode); + ssize_t length; + char tmpbuf[TMPBUFLEN]; + + if (!task) + return -ESRCH; + length = scnprintf(tmpbuf, TMPBUFLEN, "%u", + audit_get_sessionid(task)); + put_task_struct(task); + return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); +} + +static const struct file_operations proc_sessionid_operations = { + .read = proc_sessionid_read, +}; #endif #ifdef CONFIG_FAULT_INJECTION @@ -2270,7 +2290,7 @@ static const struct pid_entry tgid_base_stuff[] = { DIR("fd", S_IRUSR|S_IXUSR, fd), DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo), #ifdef CONFIG_NET - DIR("net", S_IRUGO|S_IXUSR, net), + DIR("net", S_IRUGO|S_IXUGO, net), #endif REG("environ", S_IRUSR, environ), INF("auxv", S_IRUSR, pid_auxv), @@ -2319,6 +2339,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), #endif #ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject), @@ -2649,6 +2670,7 @@ static const struct pid_entry tid_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), #endif #ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject), diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 6dc0334815f..9dfb5ff2420 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -527,13 +527,21 @@ struct pagemapread { char __user *out, *end; }; -#define PM_ENTRY_BYTES sizeof(u64) -#define PM_RESERVED_BITS 3 -#define PM_RESERVED_OFFSET (64 - PM_RESERVED_BITS) -#define PM_RESERVED_MASK (((1LL<<PM_RESERVED_BITS)-1) << PM_RESERVED_OFFSET) -#define PM_SPECIAL(nr) (((nr) << PM_RESERVED_OFFSET) & PM_RESERVED_MASK) -#define PM_NOT_PRESENT PM_SPECIAL(1LL) -#define PM_SWAP PM_SPECIAL(2LL) +#define PM_ENTRY_BYTES sizeof(u64) +#define PM_STATUS_BITS 3 +#define PM_STATUS_OFFSET (64 - PM_STATUS_BITS) +#define PM_STATUS_MASK (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET) +#define PM_STATUS(nr) (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK) +#define PM_PSHIFT_BITS 6 +#define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) +#define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) +#define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) +#define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) +#define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) + +#define PM_PRESENT PM_STATUS(4LL) +#define PM_SWAP PM_STATUS(2LL) +#define PM_NOT_PRESENT PM_PSHIFT(PAGE_SHIFT) #define PM_END_OF_BUFFER 1 static int add_to_pagemap(unsigned long addr, u64 pfn, @@ -574,7 +582,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end, u64 swap_pte_to_pagemap_entry(pte_t pte) { swp_entry_t e = pte_to_swp_entry(pte); - return PM_SWAP | swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT); + return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT); } static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, @@ -588,9 +596,11 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, u64 pfn = PM_NOT_PRESENT; pte = pte_offset_map(pmd, addr); if (is_swap_pte(*pte)) - pfn = swap_pte_to_pagemap_entry(*pte); + pfn = PM_PFRAME(swap_pte_to_pagemap_entry(*pte)) + | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP; else if (pte_present(*pte)) - pfn = pte_pfn(*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); err = add_to_pagemap(addr, pfn, pm); @@ -611,12 +621,20 @@ static struct mm_walk pagemap_walk = { /* * /proc/pid/pagemap - an array mapping virtual pages to pfns * - * For each page in the address space, this file contains one 64-bit - * entry representing the corresponding physical page frame number - * (PFN) if the page is present. If there is a swap entry for the - * physical page, then an encoding of the swap file number and the - * page's offset into the swap file are returned. If no page is - * present at all, PM_NOT_PRESENT is returned. This allows determining + * For each page in the address space, this file contains one 64-bit entry + * consisting of the following: + * + * Bits 0-55 page frame number (PFN) if present + * Bits 0-4 swap type if swapped + * Bits 5-55 swap offset if swapped + * Bits 55-60 page shift (page size = 1<<page shift) + * Bit 61 reserved for future use + * Bit 62 page swapped + * Bit 63 page present + * + * If the page is not present but in swap, then the PFN contains an + * encoding of the swap file number and the page's offset into the + * swap. Unmapped pages return a null PFN. This allows determining * precisely which pages are mapped (or in swap) and comparing mapped * pages between processes. * @@ -640,17 +658,17 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, ret = -EACCES; if (!ptrace_may_attach(task)) - goto out; + goto out_task; ret = -EINVAL; /* file position must be aligned */ if (*ppos % PM_ENTRY_BYTES) - goto out; + goto out_task; ret = 0; mm = get_task_mm(task); if (!mm) - goto out; + goto out_task; ret = -ENOMEM; uaddr = (unsigned long)buf & PAGE_MASK; @@ -658,7 +676,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, pagecount = (PAGE_ALIGN(uend) - uaddr) / PAGE_SIZE; pages = kmalloc(pagecount * sizeof(struct page *), GFP_KERNEL); if (!pages) - goto out_task; + goto out_mm; down_read(¤t->mm->mmap_sem); ret = get_user_pages(current, current->mm, uaddr, pagecount, @@ -668,6 +686,12 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, if (ret < 0) goto out_free; + if (ret != pagecount) { + pagecount = ret; + ret = -EFAULT; + goto out_pages; + } + pm.out = buf; pm.end = buf + count; @@ -699,15 +723,17 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, ret = pm.out - buf; } +out_pages: for (; pagecount; pagecount--) { page = pages[pagecount-1]; if (!PageReserved(page)) SetPageDirty(page); page_cache_release(page); } - mmput(mm); out_free: kfree(pages); +out_mm: + mmput(mm); out_task: put_task_struct(task); out: diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 00b6f0a518c..3f13d491c7c 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -340,8 +340,9 @@ static struct dentry * romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { unsigned long offset, maxoff; - int fslen, res; - struct inode *inode; + long res; + int fslen; + struct inode *inode = NULL; char fsname[ROMFS_MAXFN]; /* XXX dynamic? */ struct romfs_inode ri; const char *name; /* got from dentry */ @@ -351,7 +352,7 @@ romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) offset = dir->i_ino & ROMFH_MASK; lock_kernel(); if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) - goto out; + goto error; maxoff = romfs_maxsize(dir->i_sb); offset = be32_to_cpu(ri.spec) & ROMFH_MASK; @@ -364,9 +365,9 @@ romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) for(;;) { if (!offset || offset >= maxoff) - goto out0; + goto success; /* negative success */ if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) - goto out; + goto error; /* try to match the first 16 bytes of name */ fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE); @@ -397,23 +398,14 @@ romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) inode = romfs_iget(dir->i_sb, offset); if (IS_ERR(inode)) { res = PTR_ERR(inode); - goto out; + goto error; } - /* - * it's a bit funky, _lookup needs to return an error code - * (negative) or a NULL, both as a dentry. ENOENT should not - * be returned, instead we need to create a negative dentry by - * d_add(dentry, NULL); and return 0 as no error. - * (Although as I see, it only matters on writable file - * systems). - */ - -out0: inode = NULL; +success: + d_add(dentry, inode); res = 0; - d_add (dentry, inode); - -out: unlock_kernel(); +error: + unlock_kernel(); return ERR_PTR(res); } diff --git a/fs/super.c b/fs/super.c index 010446d8c40..d0a941a4e62 100644 --- a/fs/super.c +++ b/fs/super.c @@ -556,11 +556,11 @@ out: } /** - * mark_files_ro + * mark_files_ro - mark all files read-only * @sb: superblock in question * - * All files are marked read/only. We don't care about pending - * delete files so this should be used in 'force' mode only + * All files are marked read-only. We don't care about pending + * delete files so this should be used in 'force' mode only. */ static void mark_files_ro(struct super_block *sb) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index a271c87c447..baa663e6938 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/kobject.h> +#include <linux/kallsyms.h> #include <linux/namei.h> #include <linux/poll.h> #include <linux/list.h> @@ -86,7 +87,12 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer * The code works fine with PAGE_SIZE return but it's likely to * indicate truncated result or overflow in normal use cases. */ - BUG_ON(count >= (ssize_t)PAGE_SIZE); + if (count >= (ssize_t)PAGE_SIZE) { + print_symbol("fill_read_buffer: %s returned bad count\n", + (unsigned long)ops->show); + /* Try to struggle along */ + count = PAGE_SIZE - 1; + } if (count >= 0) { buffer->needs_read_fill = 0; buffer->count = count; diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 1fca381f0ce..1e7598fb978 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -315,8 +315,8 @@ static void ufs_change_blocknr(struct inode *inode, sector_t beg, } UFSD(" change from %llu to %llu, pos %u\n", - (unsigned long long)pos + oldb, - (unsigned long long)pos + newb, pos); + (unsigned long long)(pos + oldb), + (unsigned long long)(pos + newb), pos); bh->b_blocknr = newb + pos; unmap_underlying_metadata(bh->b_bdev, |