diff options
Diffstat (limited to 'fs')
55 files changed, 687 insertions, 718 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index 970d38f3..584bb0f 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c @@ -127,14 +127,21 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist) _enter("%s,%s", name, vllist); + down_write(&afs_cells_sem); + read_lock(&afs_cells_lock); + list_for_each_entry(cell, &afs_cells, link) { + if (strcasecmp(cell->name, name) == 0) + goto duplicate_name; + } + read_unlock(&afs_cells_lock); + cell = afs_cell_alloc(name, vllist); if (IS_ERR(cell)) { _leave(" = %ld", PTR_ERR(cell)); + up_write(&afs_cells_sem); return cell; } - down_write(&afs_cells_sem); - /* add a proc directory for this cell */ ret = afs_proc_cell_setup(cell); if (ret < 0) @@ -167,6 +174,11 @@ error: kfree(cell); _leave(" = %d", ret); return ERR_PTR(ret); + +duplicate_name: + read_unlock(&afs_cells_lock); + up_write(&afs_cells_sem); + return ERR_PTR(-EEXIST); } /* diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 5ca3625..9ba16ed 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -573,7 +573,6 @@ extern const struct file_operations afs_mntpt_file_operations; extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); extern void afs_mntpt_kill_timer(void); -extern void afs_umount_begin(struct vfsmount *, int); /* * proc.c diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index a3510b8..2f55039 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -283,11 +283,3 @@ void afs_mntpt_kill_timer(void) cancel_delayed_work(&afs_mntpt_expiry_timer); flush_scheduled_work(); } - -/* - * begin unmount by attempting to remove all automounted mountpoints we added - */ -void afs_umount_begin(struct vfsmount *vfsmnt, int flags) -{ - shrink_submounts(vfsmnt, &afs_vfsmounts); -} diff --git a/fs/afs/super.c b/fs/afs/super.c index 36bbce4..4b572b8 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -50,7 +50,6 @@ static const struct super_operations afs_super_ops = { .write_inode = afs_write_inode, .destroy_inode = afs_destroy_inode, .clear_inode = afs_clear_inode, - .umount_begin = afs_umount_begin, .put_super = afs_put_super, .show_options = generic_show_options, }; @@ -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); diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 2332188..f42be06 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -81,13 +81,10 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, if (IS_ERR(anon_inode_inode)) return -ENODEV; - file = get_empty_filp(); - if (!file) - return -ENFILE; error = get_unused_fd(); if (error < 0) - goto err_put_filp; + return error; fd = error; /* @@ -114,14 +111,15 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, dentry->d_flags &= ~DCACHE_UNHASHED; d_instantiate(dentry, anon_inode_inode); - file->f_path.mnt = mntget(anon_inode_mnt); - file->f_path.dentry = dentry; + error = -ENFILE; + file = alloc_file(anon_inode_mnt, dentry, + FMODE_READ | FMODE_WRITE, fops); + if (!file) + goto err_dput; file->f_mapping = anon_inode_inode->i_mapping; file->f_pos = 0; file->f_flags = O_RDWR; - file->f_op = fops; - file->f_mode = FMODE_READ | FMODE_WRITE; file->f_version = 0; file->private_data = priv; @@ -132,10 +130,10 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, *pfile = file; return 0; +err_dput: + dput(dentry); err_put_unused_fd: put_unused_fd(fd); -err_put_filp: - put_filp(file); return error; } EXPORT_SYMBOL_GPL(anon_inode_getfd); @@ -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 ddfdd2c..9819632 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2564,14 +2564,13 @@ int nobh_write_end(struct file *file, struct address_space *mapping, struct inode *inode = page->mapping->host; struct buffer_head *head = fsdata; struct buffer_head *bh; + BUG_ON(fsdata != NULL && page_has_buffers(page)); - if (!PageMappedToDisk(page)) { - if (unlikely(copied < len) && !page_has_buffers(page)) - attach_nobh_buffers(page, head); - if (page_has_buffers(page)) - return generic_write_end(file, mapping, pos, len, - copied, page, fsdata); - } + if (unlikely(copied < len) && !page_has_buffers(page)) + attach_nobh_buffers(page, head); + if (page_has_buffers(page)) + return generic_write_end(file, mapping, pos, len, + copied, page, fsdata); SetPageUptodate(page); set_page_dirty(page); @@ -3213,7 +3212,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 +3231,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 7f88382..56c9240 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -33,7 +33,6 @@ void dfs_shrink_umount_helper(struct vfsmount *vfsmnt) { mark_mounts_for_expiry(&cifs_dfs_automount_list); mark_mounts_for_expiry(&cifs_dfs_automount_list); - shrink_submounts(vfsmnt, &cifs_dfs_automount_list); } /** @@ -74,7 +73,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 +83,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 +126,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 +180,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 +301,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 +335,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 +343,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 +364,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 f93932c..1cb5b0a 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 @@ -261,7 +261,7 @@ static void mode_to_access_flags(umode_t mode, umode_t bits_to_use, return; } -static __le16 fill_ace_for_sid(struct cifs_ace *pntace, +static __u16 fill_ace_for_sid(struct cifs_ace *pntace, const struct cifs_sid *psid, __u64 nmode, umode_t bits) { int i; @@ -411,7 +411,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, __u64 nmode) { - __le16 size = 0; + u16 size = 0; struct cifs_acl *pnndacl; pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl)); @@ -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 0af63e6..7e5e0e7 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 4e83b47..0f5c62b 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 ef7f438..7cc86c4 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 fa849c9..40b6900 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 24eb4d3..bc673c8 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 1d6fb01..d4e7ec9 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", @@ -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 841a032..5e59658 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/efs/inode.c b/fs/efs/inode.c index 79e19e5..a8e7797 100644 --- a/fs/efs/inode.c +++ b/fs/efs/inode.c @@ -140,7 +140,7 @@ struct inode *efs_iget(struct super_block *super, unsigned long ino) brelse(bh); #ifdef DEBUG - printk(KERN_DEBUG "EFS: read_inode(): inode %lu, extents %d, mode %o\n", + printk(KERN_DEBUG "EFS: efs_iget(): inode %lu, extents %d, mode %o\n", inode->i_ino, in->numextents, inode->i_mode); #endif diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index d34e996..a754d18 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 9397d77..0e97b6e 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 fb89c29..a6ea4d6 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/file_table.c b/fs/file_table.c index 6d27bef..986ff4e 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -83,6 +83,12 @@ int proc_nr_files(ctl_table *table, int write, struct file *filp, /* Find an unused file structure and return a pointer to it. * Returns NULL, if there are no more free file structures or * we run out of memory. + * + * Be very careful using this. You are responsible for + * getting write access to any mount that you might assign + * to this filp, if it is opened for write. If this is not + * done, you will imbalance int the mount's writer count + * and a warning at __fput() time. */ struct file *get_empty_filp(void) { diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index c007607..0655767 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/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c index a1e1f0f..8601d8e 100644 --- a/fs/hppfs/hppfs_kern.c +++ b/fs/hppfs/hppfs_kern.c @@ -1,23 +1,24 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <linux/fs.h> +#include <linux/ctype.h> +#include <linux/dcache.h> #include <linux/file.h> -#include <linux/module.h> +#include <linux/fs.h> #include <linux/init.h> -#include <linux/slab.h> -#include <linux/list.h> #include <linux/kernel.h> -#include <linux/ctype.h> -#include <linux/dcache.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/mount.h> +#include <linux/slab.h> #include <linux/statfs.h> +#include <linux/types.h> #include <asm/uaccess.h> -#include <asm/fcntl.h> #include "os.h" -static int init_inode(struct inode *inode, struct dentry *dentry); +static struct inode *get_inode(struct super_block *, struct dentry *); struct hppfs_data { struct list_head list; @@ -51,14 +52,14 @@ 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)) - return(0); + if ((sb->s_op != &hppfs_sbops) || (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); + for (i = 0; i < dentry->d_name.len; i++) { + if (!isdigit(dentry->d_name.name[i])) + return 0; } - return(1); + return 1; } static char *dentry_name(struct dentry *dentry, int extra) @@ -70,8 +71,8 @@ static char *dentry_name(struct dentry *dentry, int extra) len = 0; parent = dentry; - while(parent->d_parent != parent){ - if(is_pid(parent)) + while (parent->d_parent != parent) { + if (is_pid(parent)) len += strlen("pid") + 1; else len += parent->d_name.len + 1; parent = parent->d_parent; @@ -80,12 +81,13 @@ static char *dentry_name(struct dentry *dentry, int extra) root = "proc"; len += strlen(root); name = kmalloc(len + extra + 1, GFP_KERNEL); - if(name == NULL) return(NULL); + if (name == NULL) + return NULL; name[len] = '\0'; parent = dentry; - while(parent->d_parent != parent){ - if(is_pid(parent)){ + while (parent->d_parent != parent) { + if (is_pid(parent)) { seg_name = "pid"; seg_len = strlen("pid"); } @@ -100,27 +102,25 @@ static char *dentry_name(struct dentry *dentry, int extra) parent = parent->d_parent; } strncpy(name, root, strlen(root)); - return(name); + return name; } -struct dentry_operations hppfs_dentry_ops = { -}; - 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; + if (file != NULL) + extra += strlen(file) + 1; host_file = dentry_name(dentry, extra + strlen("/remove")); - if(host_file == NULL){ - printk("file_removed : allocation failed\n"); - return(-ENOMEM); + if (host_file == NULL) { + printk(KERN_ERR "file_removed : allocation failed\n"); + return -ENOMEM; } - if(file != NULL){ + if (file != NULL) { strcat(host_file, "/"); strcat(host_file, file); } @@ -128,45 +128,11 @@ static int file_removed(struct dentry *dentry, const char *file) fd = os_open_file(host_file, of_read(OPENFLAGS()), 0); kfree(host_file); - if(fd > 0){ + if (fd > 0) { os_close_file(fd); - return(1); - } - return(0); -} - -static void hppfs_read_inode(struct inode *ino) -{ - struct inode *proc_ino; - - if(HPPFS_I(ino)->proc_dentry == NULL) - return; - - proc_ino = HPPFS_I(ino)->proc_dentry->d_inode; - ino->i_uid = proc_ino->i_uid; - ino->i_gid = proc_ino->i_gid; - ino->i_atime = proc_ino->i_atime; - ino->i_mtime = proc_ino->i_mtime; - ino->i_ctime = proc_ino->i_ctime; - ino->i_ino = proc_ino->i_ino; - ino->i_mode = proc_ino->i_mode; - ino->i_nlink = proc_ino->i_nlink; - ino->i_size = proc_ino->i_size; - ino->i_blocks = proc_ino->i_blocks; -} - -static struct inode *hppfs_iget(struct super_block *sb) -{ - struct inode *inode; - - inode = iget_locked(sb, 0); - if (!inode) - return ERR_PTR(-ENOMEM); - if (inode->i_state & I_NEW) { - hppfs_read_inode(inode); - unlock_new_inode(inode); + return 1; } - return inode; + return 0; } static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, @@ -177,55 +143,45 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, int err, deleted; deleted = file_removed(dentry, NULL); - if(deleted < 0) - return(ERR_PTR(deleted)); - else if(deleted) - return(ERR_PTR(-ENOENT)); + 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){ + if (proc_dentry == NULL) { proc_dentry = d_alloc(parent, &dentry->d_name); - if(proc_dentry == NULL){ + 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){ + if (new) { dput(proc_dentry); proc_dentry = new; } } mutex_unlock(&parent->d_inode->i_mutex); - if(IS_ERR(proc_dentry)) - return(proc_dentry); + if (IS_ERR(proc_dentry)) + return proc_dentry; - inode = hppfs_iget(ino->i_sb); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); + err = -ENOMEM; + inode = get_inode(ino->i_sb, proc_dentry); + if (!inode) goto out_dput; - } - - err = init_inode(inode, proc_dentry); - if(err) - goto out_put; - - hppfs_read_inode(inode); d_add(dentry, inode); - dentry->d_op = &hppfs_dentry_ops; - return(NULL); + return NULL; - out_put: - iput(inode); out_dput: dput(proc_dentry); out: - return(ERR_PTR(err)); + return ERR_PTR(err); } static const struct inode_operations hppfs_file_iops = { @@ -239,15 +195,16 @@ static ssize_t read_proc(struct file *file, char __user *buf, ssize_t count, read = file->f_path.dentry->d_inode->i_fop->read; - if(!is_user) + if (!is_user) set_fs(KERNEL_DS); n = (*read)(file, buf, count, &file->f_pos); - if(!is_user) + if (!is_user) set_fs(USER_DS); - if(ppos) *ppos = file->f_pos; + if (ppos) + *ppos = file->f_pos; return n; } @@ -259,24 +216,23 @@ static ssize_t hppfs_read_file(int fd, char __user *buf, ssize_t count) n = -ENOMEM; new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if(new_buf == NULL){ - printk("hppfs_read_file : kmalloc failed\n"); + if (new_buf == NULL) { + printk(KERN_ERR "hppfs_read_file : kmalloc failed\n"); goto out; } n = 0; - while(count > 0){ + while (count > 0) { cur = min_t(ssize_t, count, PAGE_SIZE); err = os_read_file(fd, new_buf, cur); - if(err < 0){ - printk("hppfs_read : read failed, errno = %d\n", - err); + if (err < 0) { + printk(KERN_ERR "hppfs_read : read failed, " + "errno = %d\n", err); n = err; goto out_free; - } - else if(err == 0) + } else if (err == 0) break; - if(copy_to_user(buf, new_buf, err)){ + if (copy_to_user(buf, new_buf, err)) { n = -EFAULT; goto out_free; } @@ -297,35 +253,36 @@ static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count, loff_t off; int err; - if(hppfs->contents != NULL){ - if(*ppos >= hppfs->len) return(0); + if (hppfs->contents != NULL) { + if (*ppos >= hppfs->len) + return 0; data = hppfs->contents; off = *ppos; - while(off >= sizeof(data->contents)){ + while (off >= sizeof(data->contents)) { data = list_entry(data->list.next, struct hppfs_data, list); off -= sizeof(data->contents); } - if(off + count > hppfs->len) + if (off + count > hppfs->len) count = hppfs->len - off; copy_to_user(buf, &data->contents[off], count); *ppos += count; - } - else if(hppfs->host_fd != -1){ + } else if (hppfs->host_fd != -1) { err = os_seek_file(hppfs->host_fd, *ppos); - if(err){ - printk("hppfs_read : seek failed, errno = %d\n", err); - return(err); + 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) + if (count > 0) *ppos += count; } else count = read_proc(hppfs->proc_file, buf, count, ppos, 1); - return(count); + return count; } static ssize_t hppfs_write(struct file *file, const char __user *buf, size_t len, @@ -342,7 +299,7 @@ static ssize_t hppfs_write(struct file *file, const char __user *buf, size_t len err = (*write)(proc_file, buf, len, &proc_file->f_pos); file->f_pos = proc_file->f_pos; - return(err); + return err; } static int open_host_sock(char *host_file, int *filter_out) @@ -354,13 +311,13 @@ static int open_host_sock(char *host_file, int *filter_out) strcpy(end, "/rw"); *filter_out = 1; fd = os_connect_socket(host_file); - if(fd > 0) - return(fd); + if (fd > 0) + return fd; strcpy(end, "/r"); *filter_out = 0; fd = os_connect_socket(host_file); - return(fd); + return fd; } static void free_contents(struct hppfs_data *head) @@ -368,9 +325,10 @@ static void free_contents(struct hppfs_data *head) struct hppfs_data *data; struct list_head *ele, *next; - if(head == NULL) return; + if (head == NULL) + return; - list_for_each_safe(ele, next, &head->list){ + list_for_each_safe(ele, next, &head->list) { data = list_entry(ele, struct hppfs_data, list); kfree(data); } @@ -387,8 +345,8 @@ static struct hppfs_data *hppfs_get_data(int fd, int filter, err = -ENOMEM; data = kmalloc(sizeof(*data), GFP_KERNEL); - if(data == NULL){ - printk("hppfs_get_data : head allocation failed\n"); + if (data == NULL) { + printk(KERN_ERR "hppfs_get_data : head allocation failed\n"); goto failed; } @@ -397,36 +355,36 @@ static struct hppfs_data *hppfs_get_data(int fd, int filter, head = data; *size_out = 0; - if(filter){ - while((n = read_proc(proc_file, data->contents, + 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("hppfs_get_data : failed to shut down " + if (err) { + printk(KERN_ERR "hppfs_get_data : failed to shut down " "socket\n"); goto failed_free; } } - while(1){ + while (1) { n = os_read_file(fd, data->contents, sizeof(data->contents)); - if(n < 0){ + if (n < 0) { err = n; - printk("hppfs_get_data : read failed, errno = %d\n", - err); + printk(KERN_ERR "hppfs_get_data : read failed, " + "errno = %d\n", err); goto failed_free; - } - else if(n == 0) + } else if (n == 0) break; *size_out += n; - if(n < sizeof(data->contents)) + if (n < sizeof(data->contents)) break; new = kmalloc(sizeof(*data), GFP_KERNEL); - if(new == 0){ - printk("hppfs_get_data : data allocation failed\n"); + if (new == 0) { + printk(KERN_ERR "hppfs_get_data : data allocation " + "failed\n"); err = -ENOMEM; goto failed_free; } @@ -435,12 +393,12 @@ static struct hppfs_data *hppfs_get_data(int fd, int filter, list_add(&new->list, &data->list); data = new; } - return(head); + return head; failed_free: free_contents(head); failed: - return(ERR_PTR(err)); + return ERR_PTR(err); } static struct hppfs_private *hppfs_data(void) @@ -448,77 +406,79 @@ static struct hppfs_private *hppfs_data(void) struct hppfs_private *data; data = kmalloc(sizeof(*data), GFP_KERNEL); - if(data == NULL) - return(data); + if (data == NULL) + return data; *data = ((struct hppfs_private ) { .host_fd = -1, .len = -1, .contents = NULL } ); - return(data); + 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); + 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 dentry *proc_dentry; + struct vfsmount *proc_mnt; char *host_file; int err, fd, type, filter; err = -ENOMEM; data = hppfs_data(); - if(data == NULL) + if (data == NULL) goto out; host_file = dentry_name(file->f_path.dentry, strlen("/rw")); - if(host_file == NULL) + 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), NULL, + 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)) + if (IS_ERR(data->proc_file)) goto out_free1; type = os_file_type(host_file); - if(type == OS_TYPE_FILE){ + if (type == OS_TYPE_FILE) { fd = os_open_file(host_file, of_read(OPENFLAGS()), 0); - if(fd >= 0) + if (fd >= 0) data->host_fd = fd; - else printk("hppfs_open : failed to open '%s', errno = %d\n", - host_file, -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){ + } else if (type == OS_TYPE_DIR) { fd = open_host_sock(host_file, &filter); - if(fd > 0){ + if (fd > 0) { data->contents = hppfs_get_data(fd, filter, data->proc_file, file, &data->len); - if(!IS_ERR(data->contents)) + if (!IS_ERR(data->contents)) data->host_fd = fd; - } - else printk("hppfs_open : failed to open a socket in " - "'%s', errno = %d\n", host_file, -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); + return 0; out_free1: kfree(host_file); @@ -526,34 +486,36 @@ static int hppfs_open(struct inode *inode, struct file *file) free_contents(data->contents); kfree(data); out: - return(err); + return err; } static int hppfs_dir_open(struct inode *inode, struct file *file) { struct hppfs_private *data; struct dentry *proc_dentry; + struct vfsmount *proc_mnt; int err; err = -ENOMEM; data = hppfs_data(); - if(data == NULL) + if (data == NULL) goto out; proc_dentry = HPPFS_I(inode)->proc_dentry; - data->proc_file = dentry_open(dget(proc_dentry), NULL, + 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)) + if (IS_ERR(data->proc_file)) goto out_free; file->private_data = data; - return(0); + return 0; out_free: kfree(data); out: - return(err); + return err; } static loff_t hppfs_llseek(struct file *file, loff_t off, int where) @@ -564,13 +526,13 @@ static loff_t hppfs_llseek(struct file *file, loff_t off, int where) loff_t ret; llseek = proc_file->f_path.dentry->d_inode->i_fop->llseek; - if(llseek != NULL){ + if (llseek != NULL) { ret = (*llseek)(proc_file, off, where); - if(ret < 0) - return(ret); + if (ret < 0) + return ret; } - return(default_llseek(file, off, where)); + return default_llseek(file, off, where); } static const struct file_operations hppfs_file_fops = { @@ -592,11 +554,11 @@ static int hppfs_filldir(void *d, const char *name, int size, { struct hppfs_dirent *dirent = d; - if(file_removed(dirent->dentry, name)) - return(0); + if (file_removed(dirent->dentry, name)) + return 0; - return((*dirent->filldir)(dirent->vfs_dirent, name, size, offset, - inode, type)); + return (*dirent->filldir)(dirent->vfs_dirent, name, size, offset, + inode, type); } static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir) @@ -607,7 +569,8 @@ static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir) struct hppfs_dirent dirent = ((struct hppfs_dirent) { .vfs_dirent = ent, .filldir = filldir, - .dentry = file->f_path.dentry } ); + .dentry = file->f_path.dentry + }); int err; readdir = proc_file->f_path.dentry->d_inode->i_fop->readdir; @@ -616,12 +579,12 @@ static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir) err = (*readdir)(proc_file, &dirent, hppfs_filldir); file->f_pos = proc_file->f_pos; - return(err); + return err; } static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync) { - return(0); + return 0; } static const struct file_operations hppfs_dir_fops = { @@ -639,7 +602,7 @@ static int hppfs_statfs(struct dentry *dentry, struct kstatfs *sf) sf->f_files = 0; sf->f_ffree = 0; sf->f_type = HPPFS_SUPER_MAGIC; - return(0); + return 0; } static struct inode *hppfs_alloc_inode(struct super_block *sb) @@ -647,12 +610,12 @@ static struct inode *hppfs_alloc_inode(struct super_block *sb) struct hppfs_inode_info *hi; hi = kmalloc(sizeof(*hi), GFP_KERNEL); - if(hi == NULL) - return(NULL); + if (!hi) + return NULL; - *hi = ((struct hppfs_inode_info) { .proc_dentry = NULL }); + hi->proc_dentry = NULL; inode_init_once(&hi->vfs_inode); - return(&hi->vfs_inode); + return &hi->vfs_inode; } void hppfs_delete_inode(struct inode *ino) @@ -665,21 +628,31 @@ 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) +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_file = dentry_open(dget(proc_dentry), NULL, O_RDONLY); + 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); @@ -694,10 +667,13 @@ 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_file = dentry_open(dget(proc_dentry), NULL, O_RDONLY); + 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; @@ -717,70 +693,72 @@ static const struct inode_operations hppfs_link_iops = { .follow_link = hppfs_follow_link, }; -static int init_inode(struct inode *inode, struct dentry *dentry) +static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) { - if(S_ISDIR(dentry->d_inode->i_mode)){ + 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)){ + } else if (S_ISLNK(dentry->d_inode->i_mode)) { inode->i_op = &hppfs_link_iops; inode->i_fop = &hppfs_file_fops; - } - else { + } else { inode->i_op = &hppfs_file_iops; inode->i_fop = &hppfs_file_fops; } HPPFS_I(inode)->proc_dentry = dentry; - return(0); + 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 0; } static int hppfs_fill_super(struct super_block *sb, void *d, int silent) { struct inode *root_inode; - struct file_system_type *procfs; - struct super_block *proc_sb; - int err; + struct vfsmount *proc_mnt; + int err = -ENOENT; - err = -ENOENT; - procfs = get_fs_type("proc"); - if(procfs == NULL) + proc_mnt = do_kern_mount("proc", 0, "proc", NULL); + if (IS_ERR(proc_mnt)) goto out; - if(list_empty(&procfs->fs_supers)) - goto out; - - proc_sb = list_entry(procfs->fs_supers.next, struct super_block, - s_instances); - sb->s_blocksize = 1024; sb->s_blocksize_bits = 10; sb->s_magic = HPPFS_SUPER_MAGIC; sb->s_op = &hppfs_sbops; - - root_inode = hppfs_iget(sb); - if (IS_ERR(root_inode)) { - err = PTR_ERR(root_inode); - goto out; - } - - err = init_inode(root_inode, proc_sb->s_root); - if(err) - goto out_put; + sb->s_fs_info = proc_mnt; err = -ENOMEM; - sb->s_root = d_alloc_root(root_inode); - if(sb->s_root == NULL) - goto out_put; + root_inode = get_inode(sb, proc_mnt->mnt_sb->s_root); + if (!root_inode) + goto out_mntput; - hppfs_read_inode(root_inode); + sb->s_root = d_alloc_root(root_inode); + if (!sb->s_root) + goto out_iput; - return(0); + return 0; - out_put: + out_iput: iput(root_inode); + out_mntput: + mntput(proc_mnt); out: return(err); } @@ -802,7 +780,7 @@ static struct file_system_type hppfs_type = { static int __init init_hppfs(void) { - return(register_filesystem(&hppfs_type)); + return register_filesystem(&hppfs_type); } static void __exit exit_hppfs(void) @@ -813,14 +791,3 @@ static void __exit exit_hppfs(void) module_init(init_hppfs) module_exit(exit_hppfs) MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index eee9487..6846785 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -954,7 +954,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size) FMODE_WRITE | FMODE_READ, &hugetlbfs_file_operations); if (!file) - goto out_inode; + goto out_dentry; /* inode is already attached */ return file; diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c index 37dbd64..defb932 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 3943a89..0e081d5 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. @@ -1619,14 +1620,14 @@ static int journal_init_journal_head_cache(void) { int retval; - J_ASSERT(journal_head_cache == 0); + J_ASSERT(journal_head_cache == NULL); journal_head_cache = kmem_cache_create("journal_head", sizeof(struct journal_head), 0, /* offset */ SLAB_TEMPORARY, /* flags */ NULL); /* ctor */ retval = 0; - if (journal_head_cache == 0) { + if (!journal_head_cache) { retval = -ENOMEM; printk(KERN_EMERG "JBD: no memory for journal_head cache\n"); } diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index 2b8edf4..43bc5e5 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/revoke.c b/fs/jbd/revoke.c index ad2eacf..d5f8eee 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c @@ -173,13 +173,13 @@ int __init journal_init_revoke_caches(void) 0, SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY, NULL); - if (revoke_record_cache == 0) + if (!revoke_record_cache) return -ENOMEM; revoke_table_cache = kmem_cache_create("revoke_table", sizeof(struct jbd_revoke_table_s), 0, SLAB_TEMPORARY, NULL); - if (revoke_table_cache == 0) { + if (!revoke_table_cache) { kmem_cache_destroy(revoke_record_cache); revoke_record_cache = NULL; return -ENOMEM; diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index c6cbb6c..2c9e8f5 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/journal.c b/fs/jbd2/journal.c index 96ba846..954cff0 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -219,7 +219,7 @@ static int jbd2_journal_start_thread(journal_t *journal) if (IS_ERR(t)) return PTR_ERR(t); - wait_event(journal->j_wait_done_commit, journal->j_task != 0); + wait_event(journal->j_wait_done_commit, journal->j_task != NULL); return 0; } @@ -231,7 +231,7 @@ static void journal_kill_thread(journal_t *journal) while (journal->j_task) { wake_up(&journal->j_wait_commit); spin_unlock(&journal->j_state_lock); - wait_event(journal->j_wait_done_commit, journal->j_task == 0); + wait_event(journal->j_wait_done_commit, journal->j_task == NULL); spin_lock(&journal->j_state_lock); } spin_unlock(&journal->j_state_lock); @@ -1969,14 +1969,14 @@ static int journal_init_jbd2_journal_head_cache(void) { int retval; - J_ASSERT(jbd2_journal_head_cache == 0); + J_ASSERT(jbd2_journal_head_cache == NULL); jbd2_journal_head_cache = kmem_cache_create("jbd2_journal_head", sizeof(struct journal_head), 0, /* offset */ SLAB_TEMPORARY, /* flags */ NULL); /* ctor */ retval = 0; - if (jbd2_journal_head_cache == 0) { + if (!jbd2_journal_head_cache) { retval = -ENOMEM; printk(KERN_EMERG "JBD: no memory for journal_head cache\n"); } @@ -2002,14 +2002,14 @@ static struct journal_head *journal_alloc_journal_head(void) atomic_inc(&nr_journal_heads); #endif ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS); - if (ret == 0) { + if (!ret) { jbd_debug(1, "out of memory for journal_head\n"); if (time_after(jiffies, last_warning + 5*HZ)) { printk(KERN_NOTICE "ENOMEM in %s, retrying.\n", __FUNCTION__); last_warning = jiffies; } - while (ret == 0) { + while (!ret) { yield(); ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS); } diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 1464113..5d0405a 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/jbd2/revoke.c b/fs/jbd2/revoke.c index df36f42..2e1453a 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -174,13 +174,13 @@ int __init jbd2_journal_init_revoke_caches(void) 0, SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY, NULL); - if (jbd2_revoke_record_cache == 0) + if (!jbd2_revoke_record_cache) return -ENOMEM; jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table", sizeof(struct jbd2_revoke_table_s), 0, SLAB_TEMPORARY, NULL); - if (jbd2_revoke_table_cache == 0) { + if (!jbd2_revoke_table_cache) { kmem_cache_destroy(jbd2_revoke_record_cache); jbd2_revoke_record_cache = NULL; return -ENOMEM; @@ -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) { @@ -106,7 +106,7 @@ * any extra contention... */ -static int link_path_walk(const char *name, struct nameidata *nd); +static int __link_path_walk(const char *name, struct nameidata *nd); /* In order to reduce some races, while at the same time doing additional * checking and hopefully speeding things up, we copy filenames to the @@ -563,6 +563,37 @@ walk_init_root(const char *name, struct nameidata *nd) return 1; } +/* + * Wrapper to retry pathname resolution whenever the underlying + * file system returns an ESTALE. + * + * Retry the whole path once, forcing real lookup requests + * instead of relying on the dcache. + */ +static __always_inline int link_path_walk(const char *name, struct nameidata *nd) +{ + struct path save = nd->path; + int result; + + /* make sure the stuff we saved doesn't go away */ + dget(save.dentry); + mntget(save.mnt); + + result = __link_path_walk(name, nd); + if (result == -ESTALE) { + /* nd->path had been dropped */ + nd->path = save; + dget(nd->path.dentry); + mntget(nd->path.mnt); + nd->flags |= LOOKUP_REVAL; + result = __link_path_walk(name, nd); + } + + path_put(&save); + + return result; +} + static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) { int res = 0; @@ -1020,36 +1051,6 @@ return_err: return err; } -/* - * Wrapper to retry pathname resolution whenever the underlying - * file system returns an ESTALE. - * - * Retry the whole path once, forcing real lookup requests - * instead of relying on the dcache. - */ -static int link_path_walk(const char *name, struct nameidata *nd) -{ - struct nameidata save = *nd; - int result; - - /* make sure the stuff we saved doesn't go away */ - dget(save.path.dentry); - mntget(save.path.mnt); - - result = __link_path_walk(name, nd); - if (result == -ESTALE) { - *nd = save; - dget(nd->path.dentry); - mntget(nd->path.mnt); - nd->flags |= LOOKUP_REVAL; - result = __link_path_walk(name, nd); - } - - path_put(&save.path); - - return result; -} - static int path_walk(const char *name, struct nameidata *nd) { current->total_link_count = 0; @@ -1364,13 +1365,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/namespace.c b/fs/namespace.c index 7953c96..94f026e 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -155,15 +155,15 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns) } } -static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd) +static void detach_mnt(struct vfsmount *mnt, struct path *old_path) { - old_nd->path.dentry = mnt->mnt_mountpoint; - old_nd->path.mnt = mnt->mnt_parent; + old_path->dentry = mnt->mnt_mountpoint; + old_path->mnt = mnt->mnt_parent; mnt->mnt_parent = mnt; mnt->mnt_mountpoint = mnt->mnt_root; list_del_init(&mnt->mnt_child); list_del_init(&mnt->mnt_hash); - old_nd->path.dentry->d_mounted--; + old_path->dentry->d_mounted--; } void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, @@ -174,12 +174,12 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, dentry->d_mounted++; } -static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd) +static void attach_mnt(struct vfsmount *mnt, struct path *path) { - mnt_set_mountpoint(nd->path.mnt, nd->path.dentry, mnt); + mnt_set_mountpoint(path->mnt, path->dentry, mnt); list_add_tail(&mnt->mnt_hash, mount_hashtable + - hash(nd->path.mnt, nd->path.dentry)); - list_add_tail(&mnt->mnt_child, &nd->path.mnt->mnt_mounts); + hash(path->mnt, path->dentry)); + list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts); } /* @@ -262,10 +262,8 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, /* stick the duplicate mount on the same expiry list * as the original if that was on one */ if (flag & CL_EXPIRE) { - spin_lock(&vfsmount_lock); if (!list_empty(&old->mnt_expire)) list_add(&mnt->mnt_expire, &old->mnt_expire); - spin_unlock(&vfsmount_lock); } } return mnt; @@ -548,6 +546,7 @@ void release_mounts(struct list_head *head) m = mnt->mnt_parent; mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; + m->mnt_ghosts--; spin_unlock(&vfsmount_lock); dput(dentry); mntput(m); @@ -572,12 +571,16 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) __touch_mnt_namespace(p->mnt_ns); p->mnt_ns = NULL; list_del_init(&p->mnt_child); - if (p->mnt_parent != p) + if (p->mnt_parent != p) { + p->mnt_parent->mnt_ghosts++; p->mnt_mountpoint->d_mounted--; + } change_mnt_propagation(p, MS_PRIVATE); } } +static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); + static int do_umount(struct vfsmount *mnt, int flags) { struct super_block *sb = mnt->mnt_sb; @@ -650,6 +653,9 @@ static int do_umount(struct vfsmount *mnt, int flags) spin_lock(&vfsmount_lock); event++; + if (!(flags & MNT_DETACH)) + shrink_submounts(mnt, &umount_list); + retval = -EBUSY; if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) { if (!list_empty(&mnt->mnt_list)) @@ -744,7 +750,7 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, int flag) { struct vfsmount *res, *p, *q, *r, *s; - struct nameidata nd; + struct path path; if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) return NULL; @@ -769,14 +775,14 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, q = q->mnt_parent; } p = s; - nd.path.mnt = q; - nd.path.dentry = p->mnt_mountpoint; + path.mnt = q; + path.dentry = p->mnt_mountpoint; q = clone_mnt(p, p->mnt_root, flag); if (!q) goto Enomem; spin_lock(&vfsmount_lock); list_add_tail(&q->mnt_list, &res->mnt_list); - attach_mnt(q, &nd); + attach_mnt(q, &path); spin_unlock(&vfsmount_lock); } } @@ -876,11 +882,11 @@ void drop_collected_mounts(struct vfsmount *mnt) * in allocations. */ static int attach_recursive_mnt(struct vfsmount *source_mnt, - struct nameidata *nd, struct nameidata *parent_nd) + struct path *path, struct path *parent_path) { LIST_HEAD(tree_list); - struct vfsmount *dest_mnt = nd->path.mnt; - struct dentry *dest_dentry = nd->path.dentry; + struct vfsmount *dest_mnt = path->mnt; + struct dentry *dest_dentry = path->dentry; struct vfsmount *child, *p; if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list)) @@ -892,9 +898,9 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, } spin_lock(&vfsmount_lock); - if (parent_nd) { - detach_mnt(source_mnt, parent_nd); - attach_mnt(source_mnt, nd); + if (parent_path) { + detach_mnt(source_mnt, parent_path); + attach_mnt(source_mnt, path); touch_mnt_namespace(current->nsproxy->mnt_ns); } else { mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); @@ -930,7 +936,7 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) err = -ENOENT; if (IS_ROOT(nd->path.dentry) || !d_unhashed(nd->path.dentry)) - err = attach_recursive_mnt(mnt, nd, NULL); + err = attach_recursive_mnt(mnt, &nd->path, NULL); out_unlock: mutex_unlock(&nd->path.dentry->d_inode->i_mutex); if (!err) @@ -1059,7 +1065,8 @@ static inline int tree_contains_unbindable(struct vfsmount *mnt) */ static noinline int do_move_mount(struct nameidata *nd, char *old_name) { - struct nameidata old_nd, parent_nd; + struct nameidata old_nd; + struct path parent_path; struct vfsmount *p; int err = 0; if (!capable(CAP_SYS_ADMIN)) @@ -1114,21 +1121,19 @@ static noinline int do_move_mount(struct nameidata *nd, char *old_name) if (p == old_nd.path.mnt) goto out1; - err = attach_recursive_mnt(old_nd.path.mnt, nd, &parent_nd); + err = attach_recursive_mnt(old_nd.path.mnt, &nd->path, &parent_path); if (err) goto out1; - spin_lock(&vfsmount_lock); /* if the mount is moved, it should no longer be expire * automatically */ list_del_init(&old_nd.path.mnt->mnt_expire); - spin_unlock(&vfsmount_lock); out1: mutex_unlock(&nd->path.dentry->d_inode->i_mutex); out: up_write(&namespace_sem); if (!err) - path_put(&parent_nd.path); + path_put(&parent_path); path_put(&old_nd.path); return err; } @@ -1189,12 +1194,9 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, if ((err = graft_tree(newmnt, nd))) goto unlock; - if (fslist) { - /* add to the specified expiration list */ - spin_lock(&vfsmount_lock); + if (fslist) /* add to the specified expiration list */ list_add_tail(&newmnt->mnt_expire, fslist); - spin_unlock(&vfsmount_lock); - } + up_write(&namespace_sem); return 0; @@ -1206,75 +1208,6 @@ unlock: EXPORT_SYMBOL_GPL(do_add_mount); -static void expire_mount(struct vfsmount *mnt, struct list_head *mounts, - struct list_head *umounts) -{ - spin_lock(&vfsmount_lock); - - /* - * Check if mount is still attached, if not, let whoever holds it deal - * with the sucker - */ - if (mnt->mnt_parent == mnt) { - spin_unlock(&vfsmount_lock); - return; - } - - /* - * Check that it is still dead: the count should now be 2 - as - * contributed by the vfsmount parent and the mntget above - */ - if (!propagate_mount_busy(mnt, 2)) { - /* delete from the namespace */ - touch_mnt_namespace(mnt->mnt_ns); - list_del_init(&mnt->mnt_list); - mnt->mnt_ns = NULL; - umount_tree(mnt, 1, umounts); - spin_unlock(&vfsmount_lock); - } else { - /* - * Someone brought it back to life whilst we didn't have any - * locks held so return it to the expiration list - */ - list_add_tail(&mnt->mnt_expire, mounts); - spin_unlock(&vfsmount_lock); - } -} - -/* - * go through the vfsmounts we've just consigned to the graveyard to - * - check that they're still dead - * - delete the vfsmount from the appropriate namespace under lock - * - dispose of the corpse - */ -static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts) -{ - struct mnt_namespace *ns; - struct vfsmount *mnt; - - while (!list_empty(graveyard)) { - LIST_HEAD(umounts); - mnt = list_first_entry(graveyard, struct vfsmount, mnt_expire); - list_del_init(&mnt->mnt_expire); - - /* don't do anything if the namespace is dead - all the - * vfsmounts from it are going away anyway */ - ns = mnt->mnt_ns; - if (!ns || !ns->root) - continue; - get_mnt_ns(ns); - - spin_unlock(&vfsmount_lock); - down_write(&namespace_sem); - expire_mount(mnt, mounts, &umounts); - up_write(&namespace_sem); - release_mounts(&umounts); - mntput(mnt); - put_mnt_ns(ns); - spin_lock(&vfsmount_lock); - } -} - /* * process a list of expirable mountpoints with the intent of discarding any * mountpoints that aren't in use and haven't been touched since last we came @@ -1284,10 +1217,12 @@ void mark_mounts_for_expiry(struct list_head *mounts) { struct vfsmount *mnt, *next; LIST_HEAD(graveyard); + LIST_HEAD(umounts); if (list_empty(mounts)) return; + down_write(&namespace_sem); spin_lock(&vfsmount_lock); /* extract from the expiration list every vfsmount that matches the @@ -1298,16 +1233,19 @@ void mark_mounts_for_expiry(struct list_head *mounts) */ list_for_each_entry_safe(mnt, next, mounts, mnt_expire) { if (!xchg(&mnt->mnt_expiry_mark, 1) || - atomic_read(&mnt->mnt_count) != 1) + propagate_mount_busy(mnt, 1)) continue; - - mntget(mnt); list_move(&mnt->mnt_expire, &graveyard); } - - expire_mount_list(&graveyard, mounts); - + while (!list_empty(&graveyard)) { + mnt = list_first_entry(&graveyard, struct vfsmount, mnt_expire); + touch_mnt_namespace(mnt->mnt_ns); + umount_tree(mnt, 1, &umounts); + } spin_unlock(&vfsmount_lock); + up_write(&namespace_sem); + + release_mounts(&umounts); } EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); @@ -1343,7 +1281,6 @@ resume: } if (!propagate_mount_busy(mnt, 1)) { - mntget(mnt); list_move_tail(&mnt->mnt_expire, graveyard); found++; } @@ -1363,22 +1300,22 @@ resume: * process a list of expirable mountpoints with the intent of discarding any * submounts of a specific parent mountpoint */ -void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts) +static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts) { LIST_HEAD(graveyard); - int found; - - spin_lock(&vfsmount_lock); + struct vfsmount *m; /* extract submounts of 'mountpoint' from the expiration list */ - while ((found = select_submounts(mountpoint, &graveyard)) != 0) - expire_mount_list(&graveyard, mounts); - - spin_unlock(&vfsmount_lock); + while (select_submounts(mnt, &graveyard)) { + while (!list_empty(&graveyard)) { + m = list_first_entry(&graveyard, struct vfsmount, + mnt_expire); + touch_mnt_namespace(mnt->mnt_ns); + umount_tree(mnt, 1, umounts); + } + } } -EXPORT_SYMBOL_GPL(shrink_submounts); - /* * Some copy_from_user() implementations do not return the exact number of * bytes remaining to copy on a fault. But copy_mount_options() requires that. @@ -1683,7 +1620,7 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) path_put(&old_pwd); } -static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) +static void chroot_fs_refs(struct path *old_root, struct path *new_root) { struct task_struct *g, *p; struct fs_struct *fs; @@ -1695,12 +1632,12 @@ static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) if (fs) { atomic_inc(&fs->count); task_unlock(p); - if (fs->root.dentry == old_nd->path.dentry - && fs->root.mnt == old_nd->path.mnt) - set_fs_root(fs, &new_nd->path); - if (fs->pwd.dentry == old_nd->path.dentry - && fs->pwd.mnt == old_nd->path.mnt) - set_fs_pwd(fs, &new_nd->path); + if (fs->root.dentry == old_root->dentry + && fs->root.mnt == old_root->mnt) + set_fs_root(fs, new_root); + if (fs->pwd.dentry == old_root->dentry + && fs->pwd.mnt == old_root->mnt) + set_fs_pwd(fs, new_root); put_fs_struct(fs); } else task_unlock(p); @@ -1737,7 +1674,8 @@ asmlinkage long sys_pivot_root(const char __user * new_root, const char __user * put_old) { struct vfsmount *tmp; - struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd; + struct nameidata new_nd, old_nd, user_nd; + struct path parent_path, root_parent; int error; if (!capable(CAP_SYS_ADMIN)) @@ -1811,19 +1749,19 @@ asmlinkage long sys_pivot_root(const char __user * new_root, goto out3; } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) goto out3; - detach_mnt(new_nd.path.mnt, &parent_nd); + detach_mnt(new_nd.path.mnt, &parent_path); detach_mnt(user_nd.path.mnt, &root_parent); /* mount old root on put_old */ - attach_mnt(user_nd.path.mnt, &old_nd); + attach_mnt(user_nd.path.mnt, &old_nd.path); /* mount new_root on / */ attach_mnt(new_nd.path.mnt, &root_parent); touch_mnt_namespace(current->nsproxy->mnt_ns); spin_unlock(&vfsmount_lock); - chroot_fs_refs(&user_nd, &new_nd); + chroot_fs_refs(&user_nd.path, &new_nd.path); security_sb_post_pivotroot(&user_nd, &new_nd); error = 0; - path_put(&root_parent.path); - path_put(&parent_nd.path); + path_put(&root_parent); + path_put(&parent_path); out2: mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); up_write(&namespace_sem); diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 3d7d963..5a70be5 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 dd4dfcd..f921902 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -589,8 +589,6 @@ static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb); struct rpc_clnt *rpc; - shrink_submounts(vfsmnt, &nfs_automount_list); - if (!(flags & MNT_FORCE)) return; /* -EIO all pending I/O */ diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 80c61fdb..bed6341 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; } @@ -903,6 +903,18 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) int error; struct file *f; + /* + * We must always pass in a valid mount pointer. Historically + * callers got away with not passing it, but we must enforce this at + * the earliest possible point now to avoid strange problems deep in the + * filesystem stack. + */ + if (!mnt) { + printk(KERN_WARNING "%s called with NULL vfsmount\n", __func__); + dump_stack(); + return ERR_PTR(-EINVAL); + } + error = -ENFILE; f = get_empty_filp(); if (f == NULL) { @@ -957,13 +957,10 @@ struct file *create_write_pipe(void) struct dentry *dentry; struct qstr name = { .name = "" }; - f = get_empty_filp(); - if (!f) - return ERR_PTR(-ENFILE); err = -ENFILE; inode = get_pipe_inode(); if (!inode) - goto err_file; + goto err; err = -ENOMEM; dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name); @@ -978,22 +975,24 @@ struct file *create_write_pipe(void) */ dentry->d_flags &= ~DCACHE_UNHASHED; d_instantiate(dentry, inode); - f->f_path.mnt = mntget(pipe_mnt); - f->f_path.dentry = dentry; + + err = -ENFILE; + f = alloc_file(pipe_mnt, dentry, FMODE_WRITE, &write_pipe_fops); + if (!f) + goto err_dentry; f->f_mapping = inode->i_mapping; f->f_flags = O_WRONLY; - f->f_op = &write_pipe_fops; - f->f_mode = FMODE_WRITE; f->f_version = 0; return f; + err_dentry: + dput(dentry); err_inode: free_pipe_info(inode); iput(inode); - err_file: - put_filp(f); + err: return ERR_PTR(err); } @@ -225,7 +225,7 @@ out: */ static inline int do_refcount_check(struct vfsmount *mnt, int count) { - int mycount = atomic_read(&mnt->mnt_count); + int mycount = atomic_read(&mnt->mnt_count) - mnt->mnt_ghosts; return (mycount > count); } diff --git a/fs/proc/base.c b/fs/proc/base.c index 770de44..81d7d14 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 @@ -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 4206454..9dfb5ff 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. * diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c index f85c5cf..7ee4208 100644 --- a/fs/reiserfs/do_balan.c +++ b/fs/reiserfs/do_balan.c @@ -283,7 +283,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h return balance_leaf_when_delete(tb, flag); zeros_num = 0; - if (flag == M_INSERT && body == 0) + if (flag == M_INSERT && !body) zeros_num = ih_item_len(ih); pos_in_item = tb->tb_path->pos_in_item; @@ -1728,7 +1728,7 @@ struct buffer_head *get_FEB(struct tree_balance *tb) struct buffer_info bi; for (i = 0; i < MAX_FEB_SIZE; i++) - if (tb->FEB[i] != 0) + if (tb->FEB[i] != NULL) break; if (i == MAX_FEB_SIZE) @@ -1827,7 +1827,7 @@ int get_left_neighbor_position(struct tree_balance *tb, int h) { int Sh_position = PATH_H_POSITION(tb->tb_path, h + 1); - RFALSE(PATH_H_PPARENT(tb->tb_path, h) == 0 || tb->FL[h] == 0, + RFALSE(PATH_H_PPARENT(tb->tb_path, h) == NULL || tb->FL[h] == NULL, "vs-12325: FL[%d](%p) or F[%d](%p) does not exist", h, tb->FL[h], h, PATH_H_PPARENT(tb->tb_path, h)); @@ -1841,7 +1841,7 @@ int get_right_neighbor_position(struct tree_balance *tb, int h) { int Sh_position = PATH_H_POSITION(tb->tb_path, h + 1); - RFALSE(PATH_H_PPARENT(tb->tb_path, h) == 0 || tb->FR[h] == 0, + RFALSE(PATH_H_PPARENT(tb->tb_path, h) == NULL || tb->FR[h] == NULL, "vs-12330: F[%d](%p) or FR[%d](%p) does not exist", h, PATH_H_PPARENT(tb->tb_path, h), h, tb->FR[h]); diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c index 0ee35c6..07d05e0 100644 --- a/fs/reiserfs/fix_node.c +++ b/fs/reiserfs/fix_node.c @@ -153,7 +153,7 @@ static void create_virtual_node(struct tree_balance *tb, int h) if (vn->vn_mode == M_INSERT) { struct virtual_item *vi = vn->vn_vi + vn->vn_affected_item_num; - RFALSE(vn->vn_ins_ih == 0, + RFALSE(vn->vn_ins_ih == NULL, "vs-8040: item header of inserted item is not specified"); vi->vi_item_len = tb->insert_size[0]; vi->vi_ih = vn->vn_ins_ih; @@ -857,7 +857,8 @@ static int get_lfree(struct tree_balance *tb, int h) struct buffer_head *l, *f; int order; - if ((f = PATH_H_PPARENT(tb->tb_path, h)) == 0 || (l = tb->FL[h]) == 0) + if ((f = PATH_H_PPARENT(tb->tb_path, h)) == NULL || + (l = tb->FL[h]) == NULL) return 0; if (f == l) @@ -878,7 +879,8 @@ static int get_rfree(struct tree_balance *tb, int h) struct buffer_head *r, *f; int order; - if ((f = PATH_H_PPARENT(tb->tb_path, h)) == 0 || (r = tb->FR[h]) == 0) + if ((f = PATH_H_PPARENT(tb->tb_path, h)) == NULL || + (r = tb->FR[h]) == NULL) return 0; if (f == r) diff --git a/fs/reiserfs/lbalance.c b/fs/reiserfs/lbalance.c index 281f806..6de060a 100644 --- a/fs/reiserfs/lbalance.c +++ b/fs/reiserfs/lbalance.c @@ -626,7 +626,7 @@ static void leaf_define_dest_src_infos(int shift_mode, struct tree_balance *tb, "vs-10250: leaf_define_dest_src_infos: shift type is unknown (%d)", shift_mode); } - RFALSE(src_bi->bi_bh == 0 || dest_bi->bi_bh == 0, + RFALSE(!src_bi->bi_bh || !dest_bi->bi_bh, "vs-10260: mode==%d, source (%p) or dest (%p) buffer is initialized incorrectly", shift_mode, src_bi->bi_bh, dest_bi->bi_bh); } diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index b378eea..8867533 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -452,7 +452,7 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th, buflen = DEH_SIZE + ROUND_UP(namelen); if (buflen > sizeof(small_buf)) { buffer = kmalloc(buflen, GFP_NOFS); - if (buffer == 0) + if (!buffer) return -ENOMEM; } else buffer = small_buf; diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index eba037b..344b9b9 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -191,28 +191,11 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode, dput(xadir); if (err) xafile = ERR_PTR(err); - return xafile; -} - -/* Opens a file pointer to the attribute associated with inode */ -static struct file *open_xa_file(const struct inode *inode, const char *name, - int flags) -{ - struct dentry *xafile; - struct file *fp; - - xafile = get_xa_file_dentry(inode, name, flags); - if (IS_ERR(xafile)) - return ERR_PTR(PTR_ERR(xafile)); else if (!xafile->d_inode) { dput(xafile); - return ERR_PTR(-ENODATA); + xafile = ERR_PTR(-ENODATA); } - - fp = dentry_open(xafile, NULL, O_RDWR); - /* dentry_open dputs the dentry if it fails */ - - return fp; + return xafile; } /* @@ -228,9 +211,8 @@ static struct file *open_xa_file(const struct inode *inode, const char *name, * we're called with i_mutex held, so there are no worries about the directory * changing underneath us. */ -static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir) +static int __xattr_readdir(struct inode *inode, void *dirent, filldir_t filldir) { - struct inode *inode = filp->f_path.dentry->d_inode; struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */ INITIALIZE_PATH(path_to_entry); struct buffer_head *bh; @@ -374,23 +356,16 @@ static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir) * */ static -int xattr_readdir(struct file *file, filldir_t filler, void *buf) +int xattr_readdir(struct inode *inode, filldir_t filler, void *buf) { - struct inode *inode = file->f_path.dentry->d_inode; - int res = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out; + int res = -ENOENT; mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR); -// down(&inode->i_zombie); - res = -ENOENT; if (!IS_DEADDIR(inode)) { lock_kernel(); - res = __xattr_readdir(file, buf, filler); + res = __xattr_readdir(inode, buf, filler); unlock_kernel(); } -// up(&inode->i_zombie); mutex_unlock(&inode->i_mutex); - out: return res; } @@ -442,7 +417,7 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, size_t buffer_size, int flags) { int err = 0; - struct file *fp; + struct dentry *dentry; struct page *page; char *data; struct address_space *mapping; @@ -460,18 +435,18 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, xahash = xattr_hash(buffer, buffer_size); open_file: - fp = open_xa_file(inode, name, flags); - if (IS_ERR(fp)) { - err = PTR_ERR(fp); + dentry = get_xa_file_dentry(inode, name, flags); + if (IS_ERR(dentry)) { + err = PTR_ERR(dentry); goto out; } - xinode = fp->f_path.dentry->d_inode; + xinode = dentry->d_inode; REISERFS_I(inode)->i_flags |= i_has_xattr_dir; /* we need to copy it off.. */ if (xinode->i_nlink > 1) { - fput(fp); + dput(dentry); err = reiserfs_xattr_del(inode, name); if (err < 0) goto out; @@ -485,7 +460,7 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, newattrs.ia_size = buffer_size; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; mutex_lock_nested(&xinode->i_mutex, I_MUTEX_XATTR); - err = notify_change(fp->f_path.dentry, &newattrs); + err = notify_change(dentry, &newattrs); if (err) goto out_filp; @@ -518,15 +493,14 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, rxh->h_hash = cpu_to_le32(xahash); } - err = reiserfs_prepare_write(fp, page, page_offset, + err = reiserfs_prepare_write(NULL, page, page_offset, page_offset + chunk + skip); if (!err) { if (buffer) memcpy(data + skip, buffer + buffer_pos, chunk); - err = - reiserfs_commit_write(fp, page, page_offset, - page_offset + chunk + - skip); + err = reiserfs_commit_write(NULL, page, page_offset, + page_offset + chunk + + skip); } unlock_page(page); reiserfs_put_page(page); @@ -548,7 +522,7 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, out_filp: mutex_unlock(&xinode->i_mutex); - fput(fp); + dput(dentry); out: return err; @@ -562,7 +536,7 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, size_t buffer_size) { ssize_t err = 0; - struct file *fp; + struct dentry *dentry; size_t isize; size_t file_pos = 0; size_t buffer_pos = 0; @@ -578,13 +552,13 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, if (get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; - fp = open_xa_file(inode, name, FL_READONLY); - if (IS_ERR(fp)) { - err = PTR_ERR(fp); + dentry = get_xa_file_dentry(inode, name, FL_READONLY); + if (IS_ERR(dentry)) { + err = PTR_ERR(dentry); goto out; } - xinode = fp->f_path.dentry->d_inode; + xinode = dentry->d_inode; isize = xinode->i_size; REISERFS_I(inode)->i_flags |= i_has_xattr_dir; @@ -652,7 +626,7 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, } out_dput: - fput(fp); + dput(dentry); out: return err; @@ -742,7 +716,6 @@ reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, /* This is called w/ inode->i_mutex downed */ int reiserfs_delete_xattrs(struct inode *inode) { - struct file *fp; struct dentry *dir, *root; int err = 0; @@ -763,15 +736,8 @@ int reiserfs_delete_xattrs(struct inode *inode) return 0; } - fp = dentry_open(dir, NULL, O_RDWR); - if (IS_ERR(fp)) { - err = PTR_ERR(fp); - /* dentry_open dputs the dentry if it fails */ - goto out; - } - lock_kernel(); - err = xattr_readdir(fp, reiserfs_delete_xattrs_filler, dir); + err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); if (err) { unlock_kernel(); goto out_dir; @@ -791,7 +757,7 @@ int reiserfs_delete_xattrs(struct inode *inode) unlock_kernel(); out_dir: - fput(fp); + dput(dir); out: if (!err) @@ -833,7 +799,6 @@ reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) { - struct file *fp; struct dentry *dir; int err = 0; struct reiserfs_chown_buf buf; @@ -857,13 +822,6 @@ int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) goto out; } - fp = dentry_open(dir, NULL, O_RDWR); - if (IS_ERR(fp)) { - err = PTR_ERR(fp); - /* dentry_open dputs the dentry if it fails */ - goto out; - } - lock_kernel(); attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME); @@ -871,7 +829,7 @@ int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) buf.attrs = attrs; buf.inode = inode; - err = xattr_readdir(fp, reiserfs_chown_xattrs_filler, &buf); + err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); if (err) { unlock_kernel(); goto out_dir; @@ -881,7 +839,7 @@ int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) unlock_kernel(); out_dir: - fput(fp); + dput(dir); out: attrs->ia_valid = ia_valid; @@ -1029,7 +987,6 @@ reiserfs_listxattr_filler(void *buf, const char *name, int namelen, */ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) { - struct file *fp; struct dentry *dir; int err = 0; struct reiserfs_listxattr_buf buf; @@ -1052,13 +1009,6 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) goto out; } - fp = dentry_open(dir, NULL, O_RDWR); - if (IS_ERR(fp)) { - err = PTR_ERR(fp); - /* dentry_open dputs the dentry if it fails */ - goto out; - } - buf.r_buf = buffer; buf.r_size = buffer ? size : 0; buf.r_pos = 0; @@ -1066,7 +1016,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) REISERFS_I(dentry->d_inode)->i_flags |= i_has_xattr_dir; - err = xattr_readdir(fp, reiserfs_listxattr_filler, &buf); + err = xattr_readdir(dir->d_inode, reiserfs_listxattr_filler, &buf); if (err) goto out_dir; @@ -1076,7 +1026,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) err = buf.r_pos; out_dir: - fput(fp); + dput(dir); out: reiserfs_read_unlock_xattr_i(dentry->d_inode); diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 00b6f0a..3f13d49 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/smbfs/smbiod.c b/fs/smbfs/smbiod.c index fae8e85..6bd9b69 100644 --- a/fs/smbfs/smbiod.c +++ b/fs/smbfs/smbiod.c @@ -206,7 +206,7 @@ int smbiod_retry(struct smb_sb_info *server) smb_close_socket(server); - if (pid == 0) { + if (!pid) { /* FIXME: this is fatal, umount? */ printk(KERN_ERR "smb_retry: no connection process\n"); server->state = CONN_RETRIED; @@ -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) @@ -945,6 +945,7 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data) put_filesystem(type); return mnt; } +EXPORT_SYMBOL_GPL(do_kern_mount); struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) { diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index a271c87..baa663e 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 1fca381..1e7598f 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, |