From 5c592cf23079602fc314bbccca42c53937e38450 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 31 Jul 2012 11:27:36 -0700 Subject: [PATCH] --- yaml --- r: 321209 b: refs/heads/master c: 5ef50c3bec20060bc114f62d6503c5d86d70bdd7 h: refs/heads/master i: 321207: 24533a5839052a9b3924688f9ad6200e8850e524 v: v3 --- [refs] | 2 +- trunk/fs/ceph/dir.c | 38 ---- trunk/fs/ceph/file.c | 62 +++--- trunk/fs/ceph/super.h | 6 +- trunk/fs/cifs/cifsglob.h | 10 - trunk/fs/cifs/cifsproto.h | 11 +- trunk/fs/cifs/cifssmb.c | 31 ++- trunk/fs/cifs/inode.c | 302 +++++++++++++--------------- trunk/fs/cifs/smb1ops.c | 24 --- trunk/fs/cifs/smb2inode.c | 39 ---- trunk/fs/cifs/smb2ops.c | 3 - trunk/fs/cifs/smb2proto.h | 8 - trunk/fs/ecryptfs/ecryptfs_kernel.h | 24 ++- trunk/fs/ecryptfs/file.c | 90 +++++---- trunk/fs/ecryptfs/inode.c | 65 +++--- trunk/fs/ecryptfs/main.c | 22 -- trunk/fs/ecryptfs/messaging.c | 136 +++++++++++-- trunk/fs/ecryptfs/miscdev.c | 98 ++++++--- trunk/fs/ecryptfs/mmap.c | 39 ++-- trunk/mm/page_alloc.c | 2 +- 20 files changed, 516 insertions(+), 496 deletions(-) diff --git a/[refs] b/[refs] index 6a096794e8be..93273e492181 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 410fc4ce8a373a3c35c73ac2c7c29f2bac6400bf +refs/heads/master: 5ef50c3bec20060bc114f62d6503c5d86d70bdd7 diff --git a/trunk/fs/ceph/dir.c b/trunk/fs/ceph/dir.c index f391f1e75414..e5b77319c97b 100644 --- a/trunk/fs/ceph/dir.c +++ b/trunk/fs/ceph/dir.c @@ -633,44 +633,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, return dentry; } -int ceph_atomic_open(struct inode *dir, struct dentry *dentry, - struct file *file, unsigned flags, umode_t mode, - int *opened) -{ - int err; - struct dentry *res = NULL; - - if (!(flags & O_CREAT)) { - if (dentry->d_name.len > NAME_MAX) - return -ENAMETOOLONG; - - err = ceph_init_dentry(dentry); - if (err < 0) - return err; - - return ceph_lookup_open(dir, dentry, file, flags, mode, opened); - } - - if (d_unhashed(dentry)) { - res = ceph_lookup(dir, dentry, 0); - if (IS_ERR(res)) - return PTR_ERR(res); - - if (res) - dentry = res; - } - - /* We don't deal with positive dentries here */ - if (dentry->d_inode) - return finish_no_open(file, res); - - *opened |= FILE_CREATED; - err = ceph_lookup_open(dir, dentry, file, flags, mode, opened); - dput(res); - - return err; -} - /* * If we do a create but get no trace back from the MDS, follow up with * a lookup (the VFS expects us to link up the provided dentry). diff --git a/trunk/fs/ceph/file.c b/trunk/fs/ceph/file.c index 1b81d6c31878..ecebbc09bfc7 100644 --- a/trunk/fs/ceph/file.c +++ b/trunk/fs/ceph/file.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -106,9 +107,6 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode) } /* - * If the filp already has private_data, that means the file was - * already opened by intent during lookup, and we do nothing. - * * If we already have the requisite capabilities, we can satisfy * the open request locally (no need to request new caps from the * MDS). We do, however, need to inform the MDS (asynchronously) @@ -207,24 +205,29 @@ int ceph_open(struct inode *inode, struct file *file) /* - * Do a lookup + open with a single request. - * - * If this succeeds, but some subsequent check in the vfs - * may_open() fails, the struct *file gets cleaned up (i.e. - * ceph_release gets called). So fear not! + * Do a lookup + open with a single request. If we get a non-existent + * file or symlink, return 1 so the VFS can retry. */ -int ceph_lookup_open(struct inode *dir, struct dentry *dentry, +int ceph_atomic_open(struct inode *dir, struct dentry *dentry, struct file *file, unsigned flags, umode_t mode, int *opened) { struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); struct ceph_mds_client *mdsc = fsc->mdsc; struct ceph_mds_request *req; - struct dentry *ret; + struct dentry *dn; int err; - dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n", - dentry, dentry->d_name.len, dentry->d_name.name, flags, mode); + dout("atomic_open %p dentry %p '%.*s' %s flags %d mode 0%o\n", + dir, dentry, dentry->d_name.len, dentry->d_name.name, + d_unhashed(dentry) ? "unhashed" : "hashed", flags, mode); + + if (dentry->d_name.len > NAME_MAX) + return -ENAMETOOLONG; + + err = ceph_init_dentry(dentry); + if (err < 0) + return err; /* do the open */ req = prepare_open_request(dir->i_sb, flags, mode); @@ -241,22 +244,31 @@ int ceph_lookup_open(struct inode *dir, struct dentry *dentry, (flags & (O_CREAT|O_TRUNC)) ? dir : NULL, req); err = ceph_handle_snapdir(req, dentry, err); - if (err) - goto out; - if ((flags & O_CREAT) && !req->r_reply_info.head->is_dentry) + if (err == 0 && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry) err = ceph_handle_notrace_create(dir, dentry); - if (err) - goto out; - err = finish_open(file, req->r_dentry, ceph_open, opened); -out: - ret = ceph_finish_lookup(req, dentry, err); - ceph_mdsc_put_request(req); - dout("ceph_lookup_open result=%p\n", ret); - if (IS_ERR(ret)) - return PTR_ERR(ret); + if (d_unhashed(dentry)) { + dn = ceph_finish_lookup(req, dentry, err); + if (IS_ERR(dn)) + err = PTR_ERR(dn); + } else { + /* we were given a hashed negative dentry */ + dn = NULL; + } + if (err) + goto out_err; + if (dn || dentry->d_inode == NULL || S_ISLNK(dentry->d_inode->i_mode)) { + /* make vfs retry on splice, ENOENT, or symlink */ + dout("atomic_open finish_no_open on dn %p\n", dn); + err = finish_no_open(file, dn); + } else { + dout("atomic_open finish_open on dn %p\n", dn); + err = finish_open(file, dentry, ceph_open, opened); + } - dput(ret); +out_err: + ceph_mdsc_put_request(req); + dout("atomic_open result=%d\n", err); return err; } diff --git a/trunk/fs/ceph/super.h b/trunk/fs/ceph/super.h index ebc95cc652be..66ebe720e40d 100644 --- a/trunk/fs/ceph/super.h +++ b/trunk/fs/ceph/super.h @@ -806,9 +806,9 @@ extern int ceph_copy_from_page_vector(struct page **pages, loff_t off, size_t len); extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags); extern int ceph_open(struct inode *inode, struct file *file); -extern int ceph_lookup_open(struct inode *dir, struct dentry *dentry, - struct file *od, unsigned flags, - umode_t mode, int *opened); +extern int ceph_atomic_open(struct inode *dir, struct dentry *dentry, + struct file *file, unsigned flags, umode_t mode, + int *opened); extern int ceph_release(struct inode *inode, struct file *filp); /* dir.c */ diff --git a/trunk/fs/cifs/cifsglob.h b/trunk/fs/cifs/cifsglob.h index 977dc0e85ccb..497da5ce704c 100644 --- a/trunk/fs/cifs/cifsglob.h +++ b/trunk/fs/cifs/cifsglob.h @@ -246,16 +246,6 @@ struct smb_version_operations { bool (*can_echo)(struct TCP_Server_Info *); /* send echo request */ int (*echo)(struct TCP_Server_Info *); - /* create directory */ - int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *, - struct cifs_sb_info *); - /* set info on created directory */ - void (*mkdir_setinfo)(struct inode *, const char *, - struct cifs_sb_info *, struct cifs_tcon *, - const unsigned int); - /* remove directory */ - int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *, - struct cifs_sb_info *); }; struct smb_version_values { diff --git a/trunk/fs/cifs/cifsproto.h b/trunk/fs/cifs/cifsproto.h index f1bbf8305d3a..cf7fb185103c 100644 --- a/trunk/fs/cifs/cifsproto.h +++ b/trunk/fs/cifs/cifsproto.h @@ -289,15 +289,18 @@ extern int CIFSSMBUnixSetFileInfo(const unsigned int xid, u16 fid, u32 pid_of_opener); extern int CIFSSMBUnixSetPathInfo(const unsigned int xid, - struct cifs_tcon *tcon, const char *file_name, + struct cifs_tcon *tcon, char *file_name, const struct cifs_unix_set_info_args *args, const struct nls_table *nls_codepage, - int remap); + int remap_special_chars); extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, - const char *name, struct cifs_sb_info *cifs_sb); + const char *newName, + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, - const char *name, struct cifs_sb_info *cifs_sb); + const char *name, const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name, __u16 type, const struct nls_table *nls_codepage, diff --git a/trunk/fs/cifs/cifssmb.c b/trunk/fs/cifs/cifssmb.c index 074923ce593d..cabc7a01f5df 100644 --- a/trunk/fs/cifs/cifssmb.c +++ b/trunk/fs/cifs/cifssmb.c @@ -948,15 +948,15 @@ CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, } int -CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, - struct cifs_sb_info *cifs_sb) +CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, + const char *dirName, const struct nls_table *nls_codepage, + int remap) { DELETE_DIRECTORY_REQ *pSMB = NULL; DELETE_DIRECTORY_RSP *pSMBr = NULL; int rc = 0; int bytes_returned; int name_len; - int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; cFYI(1, "In CIFSSMBRmDir"); RmDirRetry: @@ -966,15 +966,14 @@ CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, - PATH_MAX, cifs_sb->local_nls, - remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ - name_len = strnlen(name, PATH_MAX); + name_len = strnlen(dirName, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->DirName, name, name_len); + strncpy(pSMB->DirName, dirName, name_len); } pSMB->BufferFormat = 0x04; @@ -993,15 +992,14 @@ CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, } int -CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, - struct cifs_sb_info *cifs_sb) +CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, + const char *name, const struct nls_table *nls_codepage, int remap) { int rc = 0; CREATE_DIRECTORY_REQ *pSMB = NULL; CREATE_DIRECTORY_RSP *pSMBr = NULL; int bytes_returned; int name_len; - int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; cFYI(1, "In CIFSSMBMkDir"); MkDirRetry: @@ -1012,8 +1010,7 @@ CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, - PATH_MAX, cifs_sb->local_nls, - remap); + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ @@ -5946,7 +5943,7 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, int CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, - const char *file_name, + char *fileName, const struct cifs_unix_set_info_args *args, const struct nls_table *nls_codepage, int remap) { @@ -5967,14 +5964,14 @@ CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name, + cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(file_name, PATH_MAX); + name_len = strnlen(fileName, PATH_MAX); name_len++; /* trailing null */ - strncpy(pSMB->FileName, file_name, name_len); + strncpy(pSMB->FileName, fileName, name_len); } params = 6 + name_len; diff --git a/trunk/fs/cifs/inode.c b/trunk/fs/cifs/inode.c index 7354877fa3bd..35cb6a374a45 100644 --- a/trunk/fs/cifs/inode.c +++ b/trunk/fs/cifs/inode.c @@ -1219,153 +1219,16 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) return rc; } -static int -cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode, - const char *full_path, struct cifs_sb_info *cifs_sb, - struct cifs_tcon *tcon, const unsigned int xid) -{ - int rc = 0; - struct inode *newinode = NULL; - - if (tcon->unix_ext) - rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, - xid); - else - rc = cifs_get_inode_info(&newinode, full_path, NULL, - inode->i_sb, xid, NULL); - if (rc) - return rc; - - d_instantiate(dentry, newinode); - /* - * setting nlink not necessary except in cases where we failed to get it - * from the server or was set bogus - */ - if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2)) - set_nlink(dentry->d_inode, 2); - - mode &= ~current_umask(); - /* must turn on setgid bit if parent dir has it */ - if (inode->i_mode & S_ISGID) - mode |= S_ISGID; - - if (tcon->unix_ext) { - struct cifs_unix_set_info_args args = { - .mode = mode, - .ctime = NO_CHANGE_64, - .atime = NO_CHANGE_64, - .mtime = NO_CHANGE_64, - .device = 0, - }; - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { - args.uid = (__u64)current_fsuid(); - if (inode->i_mode & S_ISGID) - args.gid = (__u64)inode->i_gid; - else - args.gid = (__u64)current_fsgid(); - } else { - args.uid = NO_CHANGE_64; - args.gid = NO_CHANGE_64; - } - CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, - cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - } else { - struct TCP_Server_Info *server = tcon->ses->server; - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && - (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo) - server->ops->mkdir_setinfo(newinode, full_path, cifs_sb, - tcon, xid); - if (dentry->d_inode) { - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) - dentry->d_inode->i_mode = (mode | S_IFDIR); - - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { - dentry->d_inode->i_uid = current_fsuid(); - if (inode->i_mode & S_ISGID) - dentry->d_inode->i_gid = inode->i_gid; - else - dentry->d_inode->i_gid = - current_fsgid(); - } - } - } - return rc; -} - -static int -cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, - const char *full_path, struct cifs_sb_info *cifs_sb, - struct cifs_tcon *tcon, const unsigned int xid) -{ - int rc = 0; - u32 oplock = 0; - FILE_UNIX_BASIC_INFO *info = NULL; - struct inode *newinode = NULL; - struct cifs_fattr fattr; - - info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); - if (info == NULL) { - rc = -ENOMEM; - goto posix_mkdir_out; - } - - mode &= ~current_umask(); - rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, - NULL /* netfid */, info, &oplock, full_path, - cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - if (rc == -EOPNOTSUPP) - goto posix_mkdir_out; - else if (rc) { - cFYI(1, "posix mkdir returned 0x%x", rc); - d_drop(dentry); - goto posix_mkdir_out; - } - - if (info->Type == cpu_to_le32(-1)) - /* no return info, go query for it */ - goto posix_mkdir_get_info; - /* - * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if - * need to set uid/gid. - */ - - cifs_unix_basic_to_fattr(&fattr, info, cifs_sb); - cifs_fill_uniqueid(inode->i_sb, &fattr); - newinode = cifs_iget(inode->i_sb, &fattr); - if (!newinode) - goto posix_mkdir_get_info; - - d_instantiate(dentry, newinode); - -#ifdef CONFIG_CIFS_DEBUG2 - cFYI(1, "instantiated dentry %p %s to inode %p", dentry, - dentry->d_name.name, newinode); - - if (newinode->i_nlink != 2) - cFYI(1, "unexpected number of links %d", newinode->i_nlink); -#endif - -posix_mkdir_out: - kfree(info); - return rc; -posix_mkdir_get_info: - rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon, - xid); - goto posix_mkdir_out; -} - int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) { - int rc = 0; + int rc = 0, tmprc; unsigned int xid; struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; struct cifs_tcon *tcon; - struct TCP_Server_Info *server; - char *full_path; + char *full_path = NULL; + struct inode *newinode = NULL; + struct cifs_fattr fattr; cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode); @@ -1385,29 +1248,145 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))) { - rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb, - tcon, xid); - if (rc != -EOPNOTSUPP) + u32 oplock = 0; + FILE_UNIX_BASIC_INFO *pInfo = + kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); + if (pInfo == NULL) { + rc = -ENOMEM; goto mkdir_out; - } + } - server = tcon->ses->server; + mode &= ~current_umask(); + rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, + mode, NULL /* netfid */, pInfo, &oplock, + full_path, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc == -EOPNOTSUPP) { + kfree(pInfo); + goto mkdir_retry_old; + } else if (rc) { + cFYI(1, "posix mkdir returned 0x%x", rc); + d_drop(direntry); + } else { + if (pInfo->Type == cpu_to_le32(-1)) { + /* no return info, go query for it */ + kfree(pInfo); + goto mkdir_get_info; + } +/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need + to set uid/gid */ + + cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); + cifs_fill_uniqueid(inode->i_sb, &fattr); + newinode = cifs_iget(inode->i_sb, &fattr); + if (!newinode) { + kfree(pInfo); + goto mkdir_get_info; + } + + d_instantiate(direntry, newinode); - if (!server->ops->mkdir) { - rc = -ENOSYS; +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, "instantiated dentry %p %s to inode %p", + direntry, direntry->d_name.name, newinode); + + if (newinode->i_nlink != 2) + cFYI(1, "unexpected number of links %d", + newinode->i_nlink); +#endif + } + kfree(pInfo); goto mkdir_out; } - +mkdir_retry_old: /* BB add setting the equivalent of mode via CreateX w/ACLs */ - rc = server->ops->mkdir(xid, tcon, full_path, cifs_sb); + rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { cFYI(1, "cifs_mkdir returned 0x%x", rc); d_drop(direntry); - goto mkdir_out; + } else { +mkdir_get_info: + if (tcon->unix_ext) + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb, xid); + else + rc = cifs_get_inode_info(&newinode, full_path, NULL, + inode->i_sb, xid, NULL); + + d_instantiate(direntry, newinode); + /* setting nlink not necessary except in cases where we + * failed to get it from the server or was set bogus */ + if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) + set_nlink(direntry->d_inode, 2); + + mode &= ~current_umask(); + /* must turn on setgid bit if parent dir has it */ + if (inode->i_mode & S_ISGID) + mode |= S_ISGID; + + if (tcon->unix_ext) { + struct cifs_unix_set_info_args args = { + .mode = mode, + .ctime = NO_CHANGE_64, + .atime = NO_CHANGE_64, + .mtime = NO_CHANGE_64, + .device = 0, + }; + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { + args.uid = (__u64)current_fsuid(); + if (inode->i_mode & S_ISGID) + args.gid = (__u64)inode->i_gid; + else + args.gid = (__u64)current_fsgid(); + } else { + args.uid = NO_CHANGE_64; + args.gid = NO_CHANGE_64; + } + CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + } else { + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && + (mode & S_IWUGO) == 0) { + FILE_BASIC_INFO pInfo; + struct cifsInodeInfo *cifsInode; + u32 dosattrs; + + memset(&pInfo, 0, sizeof(pInfo)); + cifsInode = CIFS_I(newinode); + dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; + pInfo.Attributes = cpu_to_le32(dosattrs); + tmprc = CIFSSMBSetPathInfo(xid, tcon, + full_path, &pInfo, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + if (tmprc == 0) + cifsInode->cifsAttrs = dosattrs; + } + if (direntry->d_inode) { + if (cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_DYNPERM) + direntry->d_inode->i_mode = + (mode | S_IFDIR); + + if (cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_SET_UID) { + direntry->d_inode->i_uid = + current_fsuid(); + if (inode->i_mode & S_ISGID) + direntry->d_inode->i_gid = + inode->i_gid; + else + direntry->d_inode->i_gid = + current_fsgid(); + } + } + } } - - rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon, - xid); mkdir_out: /* * Force revalidate to get parent dir info when needed since cached @@ -1426,8 +1405,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) unsigned int xid; struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; - struct cifs_tcon *tcon; - struct TCP_Server_Info *server; + struct cifs_tcon *pTcon; char *full_path = NULL; struct cifsInodeInfo *cifsInode; @@ -1447,16 +1425,10 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) rc = PTR_ERR(tlink); goto rmdir_exit; } - tcon = tlink_tcon(tlink); - server = tcon->ses->server; - - if (!server->ops->rmdir) { - rc = -ENOSYS; - cifs_put_tlink(tlink); - goto rmdir_exit; - } + pTcon = tlink_tcon(tlink); - rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb); + rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_put_tlink(tlink); if (!rc) { diff --git a/trunk/fs/cifs/smb1ops.c b/trunk/fs/cifs/smb1ops.c index 3129ac74b819..c40356d24c5c 100644 --- a/trunk/fs/cifs/smb1ops.c +++ b/trunk/fs/cifs/smb1ops.c @@ -586,27 +586,6 @@ cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon) #endif } -static void -cifs_mkdir_setinfo(struct inode *inode, const char *full_path, - struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, - const unsigned int xid) -{ - FILE_BASIC_INFO info; - struct cifsInodeInfo *cifsInode; - u32 dosattrs; - int rc; - - memset(&info, 0, sizeof(info)); - cifsInode = CIFS_I(inode); - dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; - info.Attributes = cpu_to_le32(dosattrs); - rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - if (rc == 0) - cifsInode->cifsAttrs = dosattrs; -} - struct smb_version_operations smb1_operations = { .send_cancel = send_nt_cancel, .compare_fids = cifs_compare_fids, @@ -641,9 +620,6 @@ struct smb_version_operations smb1_operations = { .get_srv_inum = cifs_get_srv_inum, .build_path_to_root = cifs_build_path_to_root, .echo = CIFSSMBEcho, - .mkdir = CIFSSMBMkDir, - .mkdir_setinfo = cifs_mkdir_setinfo, - .rmdir = CIFSSMBRmDir, }; struct smb_version_values smb1_values = { diff --git a/trunk/fs/cifs/smb2inode.c b/trunk/fs/cifs/smb2inode.c index 2aa5cb08c526..1ba5c405315c 100644 --- a/trunk/fs/cifs/smb2inode.c +++ b/trunk/fs/cifs/smb2inode.c @@ -122,42 +122,3 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, kfree(smb2_data); return rc; } - -int -smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, - struct cifs_sb_info *cifs_sb) -{ - return smb2_open_op_close(xid, tcon, cifs_sb, name, - FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0, - CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR); -} - -void -smb2_mkdir_setinfo(struct inode *inode, const char *name, - struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, - const unsigned int xid) -{ - FILE_BASIC_INFO data; - struct cifsInodeInfo *cifs_i; - u32 dosattrs; - int tmprc; - - memset(&data, 0, sizeof(data)); - cifs_i = CIFS_I(inode); - dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; - data.Attributes = cpu_to_le32(dosattrs); - tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name, - FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0, - CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO); - if (tmprc == 0) - cifs_i->cifsAttrs = dosattrs; -} - -int -smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, - struct cifs_sb_info *cifs_sb) -{ - return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, - 0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE, - NULL, SMB2_OP_DELETE); -} diff --git a/trunk/fs/cifs/smb2ops.c b/trunk/fs/cifs/smb2ops.c index 826209bf3684..410cf925ea26 100644 --- a/trunk/fs/cifs/smb2ops.c +++ b/trunk/fs/cifs/smb2ops.c @@ -318,9 +318,6 @@ struct smb_version_operations smb21_operations = { .query_path_info = smb2_query_path_info, .get_srv_inum = smb2_get_srv_inum, .build_path_to_root = smb2_build_path_to_root, - .mkdir = smb2_mkdir, - .mkdir_setinfo = smb2_mkdir_setinfo, - .rmdir = smb2_rmdir, }; struct smb_version_values smb21_values = { diff --git a/trunk/fs/cifs/smb2proto.h b/trunk/fs/cifs/smb2proto.h index bfaa7b148afd..902bbe2b5ad3 100644 --- a/trunk/fs/cifs/smb2proto.h +++ b/trunk/fs/cifs/smb2proto.h @@ -52,14 +52,6 @@ extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const char *full_path, FILE_ALL_INFO *data, bool *adjust_tz); -extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, - const char *name, struct cifs_sb_info *cifs_sb); -extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path, - struct cifs_sb_info *cifs_sb, - struct cifs_tcon *tcon, const unsigned int xid); -extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, - const char *name, struct cifs_sb_info *cifs_sb); - /* * SMB2 Worker functions - most of protocol specific implementation details * are contained within these calls. diff --git a/trunk/fs/ecryptfs/ecryptfs_kernel.h b/trunk/fs/ecryptfs/ecryptfs_kernel.h index cfb4b9fed520..989e034f02bd 100644 --- a/trunk/fs/ecryptfs/ecryptfs_kernel.h +++ b/trunk/fs/ecryptfs/ecryptfs_kernel.h @@ -385,6 +385,8 @@ struct ecryptfs_msg_ctx { struct mutex mux; }; +struct ecryptfs_daemon; + struct ecryptfs_daemon { #define ECRYPTFS_DAEMON_IN_READ 0x00000001 #define ECRYPTFS_DAEMON_IN_POLL 0x00000002 @@ -392,7 +394,10 @@ struct ecryptfs_daemon { #define ECRYPTFS_DAEMON_MISCDEV_OPEN 0x00000008 u32 flags; u32 num_queued_msg_ctx; - struct file *file; + struct pid *pid; + uid_t euid; + struct user_namespace *user_ns; + struct task_struct *task; struct mutex mux; struct list_head msg_ctx_out_queue; wait_queue_head_t wait; @@ -549,8 +554,6 @@ extern struct kmem_cache *ecryptfs_key_tfm_cache; struct inode *ecryptfs_get_inode(struct inode *lower_inode, struct super_block *sb); void ecryptfs_i_size_init(const char *page_virt, struct inode *inode); -int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, - struct inode *ecryptfs_inode); int ecryptfs_decode_and_decrypt_filename(char **decrypted_name, size_t *decrypted_name_size, struct dentry *ecryptfs_dentry, @@ -604,8 +607,13 @@ int ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags); int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode); -int ecryptfs_process_response(struct ecryptfs_daemon *daemon, - struct ecryptfs_message *msg, u32 seq); +int ecryptfs_process_helo(uid_t euid, struct user_namespace *user_ns, + struct pid *pid); +int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns, + struct pid *pid); +int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, + struct user_namespace *user_ns, struct pid *pid, + u32 seq); int ecryptfs_send_message(char *data, int data_len, struct ecryptfs_msg_ctx **msg_ctx); int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx, @@ -650,7 +658,8 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs, struct inode *ecryptfs_inode); struct page *ecryptfs_get_locked_page(struct inode *inode, loff_t index); int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon); -int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon); +int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid, + struct user_namespace *user_ns); int ecryptfs_parse_packet_length(unsigned char *data, size_t *size, size_t *length_size); int ecryptfs_write_packet_length(char *dest, size_t size, @@ -662,7 +671,8 @@ int ecryptfs_send_miscdev(char *data, size_t data_size, u16 msg_flags, struct ecryptfs_daemon *daemon); void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx); int -ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, struct file *file); +ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid, + struct user_namespace *user_ns, struct pid *pid); int ecryptfs_init_kthread(void); void ecryptfs_destroy_kthread(void); int ecryptfs_privileged_open(struct file **lower_file, diff --git a/trunk/fs/ecryptfs/file.c b/trunk/fs/ecryptfs/file.c index 44ce5c6a541d..2b17f2f9b121 100644 --- a/trunk/fs/ecryptfs/file.c +++ b/trunk/fs/ecryptfs/file.c @@ -138,50 +138,29 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir) return rc; } -struct kmem_cache *ecryptfs_file_info_cache; - -static int read_or_initialize_metadata(struct dentry *dentry) +static void ecryptfs_vma_close(struct vm_area_struct *vma) { - struct inode *inode = dentry->d_inode; - struct ecryptfs_mount_crypt_stat *mount_crypt_stat; - struct ecryptfs_crypt_stat *crypt_stat; - int rc; + filemap_write_and_wait(vma->vm_file->f_mapping); +} - crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; - mount_crypt_stat = &ecryptfs_superblock_to_private( - inode->i_sb)->mount_crypt_stat; - mutex_lock(&crypt_stat->cs_mutex); +static const struct vm_operations_struct ecryptfs_file_vm_ops = { + .close = ecryptfs_vma_close, + .fault = filemap_fault, +}; - if (crypt_stat->flags & ECRYPTFS_POLICY_APPLIED && - crypt_stat->flags & ECRYPTFS_KEY_VALID) { - rc = 0; - goto out; - } +static int ecryptfs_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + int rc; - rc = ecryptfs_read_metadata(dentry); + rc = generic_file_mmap(file, vma); if (!rc) - goto out; - - if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED) { - crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED - | ECRYPTFS_ENCRYPTED); - rc = 0; - goto out; - } + vma->vm_ops = &ecryptfs_file_vm_ops; - if (!(mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) && - !i_size_read(ecryptfs_inode_to_lower(inode))) { - rc = ecryptfs_initialize_file(dentry, inode); - if (!rc) - goto out; - } - - rc = -EIO; -out: - mutex_unlock(&crypt_stat->cs_mutex); return rc; } +struct kmem_cache *ecryptfs_file_info_cache; + /** * ecryptfs_open * @inode: inode speciying file to open @@ -257,9 +236,32 @@ static int ecryptfs_open(struct inode *inode, struct file *file) rc = 0; goto out; } - rc = read_or_initialize_metadata(ecryptfs_dentry); - if (rc) - goto out_put; + mutex_lock(&crypt_stat->cs_mutex); + if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) + || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { + rc = ecryptfs_read_metadata(ecryptfs_dentry); + if (rc) { + ecryptfs_printk(KERN_DEBUG, + "Valid headers not found\n"); + if (!(mount_crypt_stat->flags + & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { + rc = -EIO; + printk(KERN_WARNING "Either the lower file " + "is not in a valid eCryptfs format, " + "or the key could not be retrieved. " + "Plaintext passthrough mode is not " + "enabled; returning -EIO\n"); + mutex_unlock(&crypt_stat->cs_mutex); + goto out_put; + } + rc = 0; + crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED + | ECRYPTFS_ENCRYPTED); + mutex_unlock(&crypt_stat->cs_mutex); + goto out; + } + } + mutex_unlock(&crypt_stat->cs_mutex); ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = " "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, (unsigned long long)i_size_read(inode)); @@ -290,7 +292,15 @@ static int ecryptfs_release(struct inode *inode, struct file *file) static int ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) { - return vfs_fsync(ecryptfs_file_to_lower(file), datasync); + int rc = 0; + + rc = generic_file_fsync(file, start, end, datasync); + if (rc) + goto out; + rc = vfs_fsync_range(ecryptfs_file_to_lower(file), start, end, + datasync); +out: + return rc; } static int ecryptfs_fasync(int fd, struct file *file, int flag) @@ -359,7 +369,7 @@ const struct file_operations ecryptfs_main_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = ecryptfs_compat_ioctl, #endif - .mmap = generic_file_mmap, + .mmap = ecryptfs_file_mmap, .open = ecryptfs_open, .flush = ecryptfs_flush, .release = ecryptfs_release, diff --git a/trunk/fs/ecryptfs/inode.c b/trunk/fs/ecryptfs/inode.c index 534b129ea676..c3ca12c33ca2 100644 --- a/trunk/fs/ecryptfs/inode.c +++ b/trunk/fs/ecryptfs/inode.c @@ -143,31 +143,6 @@ static int ecryptfs_interpose(struct dentry *lower_dentry, return 0; } -static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry, - struct inode *inode) -{ - struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); - struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); - struct dentry *lower_dir_dentry; - int rc; - - dget(lower_dentry); - lower_dir_dentry = lock_parent(lower_dentry); - rc = vfs_unlink(lower_dir_inode, lower_dentry); - if (rc) { - printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); - goto out_unlock; - } - fsstack_copy_attr_times(dir, lower_dir_inode); - set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink); - inode->i_ctime = dir->i_ctime; - d_drop(dentry); -out_unlock: - unlock_dir(lower_dir_dentry); - dput(lower_dentry); - return rc; -} - /** * ecryptfs_do_create * @directory_inode: inode of the new file's dentry's parent in ecryptfs @@ -207,10 +182,8 @@ ecryptfs_do_create(struct inode *directory_inode, } inode = __ecryptfs_get_inode(lower_dentry->d_inode, directory_inode->i_sb); - if (IS_ERR(inode)) { - vfs_unlink(lower_dir_dentry->d_inode, lower_dentry); + if (IS_ERR(inode)) goto out_lock; - } fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode); fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode); out_lock: @@ -227,8 +200,8 @@ ecryptfs_do_create(struct inode *directory_inode, * * Returns zero on success */ -int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, - struct inode *ecryptfs_inode) +static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, + struct inode *ecryptfs_inode) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; @@ -291,9 +264,7 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, * that this on disk file is prepared to be an ecryptfs file */ rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode); if (rc) { - ecryptfs_do_unlink(directory_inode, ecryptfs_dentry, - ecryptfs_inode); - make_bad_inode(ecryptfs_inode); + drop_nlink(ecryptfs_inode); unlock_new_inode(ecryptfs_inode); iput(ecryptfs_inode); goto out; @@ -495,7 +466,27 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir, static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry) { - return ecryptfs_do_unlink(dir, dentry, dentry->d_inode); + int rc = 0; + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); + struct dentry *lower_dir_dentry; + + dget(lower_dentry); + lower_dir_dentry = lock_parent(lower_dentry); + rc = vfs_unlink(lower_dir_inode, lower_dentry); + if (rc) { + printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); + goto out_unlock; + } + fsstack_copy_attr_times(dir, lower_dir_inode); + set_nlink(dentry->d_inode, + ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink); + dentry->d_inode->i_ctime = dir->i_ctime; + d_drop(dentry); +out_unlock: + unlock_dir(lower_dir_dentry); + dput(lower_dentry); + return rc; } static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, @@ -970,6 +961,12 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) goto out; } + if (S_ISREG(inode->i_mode)) { + rc = filemap_write_and_wait(inode->i_mapping); + if (rc) + goto out; + fsstack_copy_attr_all(inode, lower_inode); + } memcpy(&lower_ia, ia, sizeof(lower_ia)); if (ia->ia_valid & ATTR_FILE) lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file); diff --git a/trunk/fs/ecryptfs/main.c b/trunk/fs/ecryptfs/main.c index 2768138eefee..1c0b3b6b75c6 100644 --- a/trunk/fs/ecryptfs/main.c +++ b/trunk/fs/ecryptfs/main.c @@ -279,7 +279,6 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, char *fnek_src; char *cipher_key_bytes_src; char *fn_cipher_key_bytes_src; - u8 cipher_code; *check_ruid = 0; @@ -421,18 +420,6 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, && !fn_cipher_key_bytes_set) mount_crypt_stat->global_default_fn_cipher_key_bytes = mount_crypt_stat->global_default_cipher_key_size; - - cipher_code = ecryptfs_code_for_cipher_string( - mount_crypt_stat->global_default_cipher_name, - mount_crypt_stat->global_default_cipher_key_size); - if (!cipher_code) { - ecryptfs_printk(KERN_ERR, - "eCryptfs doesn't support cipher: %s", - mount_crypt_stat->global_default_cipher_name); - rc = -EINVAL; - goto out; - } - mutex_lock(&key_tfm_list_mutex); if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name, NULL)) { @@ -553,15 +540,6 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags } ecryptfs_set_superblock_lower(s, path.dentry->d_sb); - - /** - * Set the POSIX ACL flag based on whether they're enabled in the lower - * mount. Force a read-only eCryptfs mount if the lower mount is ro. - * Allow a ro eCryptfs mount even when the lower mount is rw. - */ - s->s_flags = flags & ~MS_POSIXACL; - s->s_flags |= path.dentry->d_sb->s_flags & (MS_RDONLY | MS_POSIXACL); - s->s_maxbytes = path.dentry->d_sb->s_maxbytes; s->s_blocksize = path.dentry->d_sb->s_blocksize; s->s_magic = ECRYPTFS_SUPER_MAGIC; diff --git a/trunk/fs/ecryptfs/messaging.c b/trunk/fs/ecryptfs/messaging.c index b29bb8bfa8d9..a750f957b145 100644 --- a/trunk/fs/ecryptfs/messaging.c +++ b/trunk/fs/ecryptfs/messaging.c @@ -32,8 +32,8 @@ static struct mutex ecryptfs_msg_ctx_lists_mux; static struct hlist_head *ecryptfs_daemon_hash; struct mutex ecryptfs_daemon_hash_mux; static int ecryptfs_hash_bits; -#define ecryptfs_current_euid_hash(uid) \ - hash_long((unsigned long)current_euid(), ecryptfs_hash_bits) +#define ecryptfs_uid_hash(uid) \ + hash_long((unsigned long)uid, ecryptfs_hash_bits) static u32 ecryptfs_msg_counter; static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr; @@ -105,24 +105,26 @@ void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx) /** * ecryptfs_find_daemon_by_euid + * @euid: The effective user id which maps to the desired daemon id + * @user_ns: The namespace in which @euid applies * @daemon: If return value is zero, points to the desired daemon pointer * * Must be called with ecryptfs_daemon_hash_mux held. * - * Search the hash list for the current effective user id. + * Search the hash list for the given user id. * * Returns zero if the user id exists in the list; non-zero otherwise. */ -int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon) +int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid, + struct user_namespace *user_ns) { struct hlist_node *elem; int rc; hlist_for_each_entry(*daemon, elem, - &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()], - euid_chain) { - if ((*daemon)->file->f_cred->euid == current_euid() && - (*daemon)->file->f_cred->user_ns == current_user_ns()) { + &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)], + euid_chain) { + if ((*daemon)->euid == euid && (*daemon)->user_ns == user_ns) { rc = 0; goto out; } @@ -135,7 +137,9 @@ int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon) /** * ecryptfs_spawn_daemon - Create and initialize a new daemon struct * @daemon: Pointer to set to newly allocated daemon struct - * @file: File used when opening /dev/ecryptfs + * @euid: Effective user id for the daemon + * @user_ns: The namespace in which @euid applies + * @pid: Process id for the daemon * * Must be called ceremoniously while in possession of * ecryptfs_sacred_daemon_hash_mux @@ -143,7 +147,8 @@ int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon) * Returns zero on success; non-zero otherwise */ int -ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, struct file *file) +ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid, + struct user_namespace *user_ns, struct pid *pid) { int rc = 0; @@ -154,13 +159,16 @@ ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, struct file *file) "GFP_KERNEL memory\n", __func__, sizeof(**daemon)); goto out; } - (*daemon)->file = file; + (*daemon)->euid = euid; + (*daemon)->user_ns = get_user_ns(user_ns); + (*daemon)->pid = get_pid(pid); + (*daemon)->task = current; mutex_init(&(*daemon)->mux); INIT_LIST_HEAD(&(*daemon)->msg_ctx_out_queue); init_waitqueue_head(&(*daemon)->wait); (*daemon)->num_queued_msg_ctx = 0; hlist_add_head(&(*daemon)->euid_chain, - &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()]); + &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)]); out: return rc; } @@ -180,6 +188,9 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon) if ((daemon->flags & ECRYPTFS_DAEMON_IN_READ) || (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)) { rc = -EBUSY; + printk(KERN_WARNING "%s: Attempt to destroy daemon with pid " + "[0x%p], but it is in the midst of a read or a poll\n", + __func__, daemon->pid); mutex_unlock(&daemon->mux); goto out; } @@ -192,16 +203,55 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon) ecryptfs_msg_ctx_alloc_to_free(msg_ctx); } hlist_del(&daemon->euid_chain); + if (daemon->task) + wake_up_process(daemon->task); + if (daemon->pid) + put_pid(daemon->pid); + if (daemon->user_ns) + put_user_ns(daemon->user_ns); mutex_unlock(&daemon->mux); kzfree(daemon); out: return rc; } +/** + * ecryptfs_process_quit + * @euid: The user ID owner of the message + * @user_ns: The namespace in which @euid applies + * @pid: The process ID for the userspace program that sent the + * message + * + * Deletes the corresponding daemon for the given euid and pid, if + * it is the registered that is requesting the deletion. Returns zero + * after deleting the desired daemon; non-zero otherwise. + */ +int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns, + struct pid *pid) +{ + struct ecryptfs_daemon *daemon; + int rc; + + mutex_lock(&ecryptfs_daemon_hash_mux); + rc = ecryptfs_find_daemon_by_euid(&daemon, euid, user_ns); + if (rc || !daemon) { + rc = -EINVAL; + printk(KERN_ERR "Received request from user [%d] to " + "unregister unrecognized daemon [0x%p]\n", euid, pid); + goto out_unlock; + } + rc = ecryptfs_exorcise_daemon(daemon); +out_unlock: + mutex_unlock(&ecryptfs_daemon_hash_mux); + return rc; +} + /** * ecryptfs_process_reponse * @msg: The ecryptfs message received; the caller should sanity check * msg->data_len and free the memory + * @pid: The process ID of the userspace application that sent the + * message * @seq: The sequence number of the message; must match the sequence * number for the existing message context waiting for this * response @@ -220,11 +270,16 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon) * * Returns zero on success; non-zero otherwise */ -int ecryptfs_process_response(struct ecryptfs_daemon *daemon, - struct ecryptfs_message *msg, u32 seq) +int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, + struct user_namespace *user_ns, struct pid *pid, + u32 seq) { + struct ecryptfs_daemon *uninitialized_var(daemon); struct ecryptfs_msg_ctx *msg_ctx; size_t msg_size; + struct nsproxy *nsproxy; + struct user_namespace *tsk_user_ns; + uid_t ctx_euid; int rc; if (msg->index >= ecryptfs_message_buf_len) { @@ -237,6 +292,51 @@ int ecryptfs_process_response(struct ecryptfs_daemon *daemon, } msg_ctx = &ecryptfs_msg_ctx_arr[msg->index]; mutex_lock(&msg_ctx->mux); + mutex_lock(&ecryptfs_daemon_hash_mux); + rcu_read_lock(); + nsproxy = task_nsproxy(msg_ctx->task); + if (nsproxy == NULL) { + rc = -EBADMSG; + printk(KERN_ERR "%s: Receiving process is a zombie. Dropping " + "message.\n", __func__); + rcu_read_unlock(); + mutex_unlock(&ecryptfs_daemon_hash_mux); + goto wake_up; + } + tsk_user_ns = __task_cred(msg_ctx->task)->user_ns; + ctx_euid = task_euid(msg_ctx->task); + rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns); + rcu_read_unlock(); + mutex_unlock(&ecryptfs_daemon_hash_mux); + if (rc) { + rc = -EBADMSG; + printk(KERN_WARNING "%s: User [%d] received a " + "message response from process [0x%p] but does " + "not have a registered daemon\n", __func__, + ctx_euid, pid); + goto wake_up; + } + if (ctx_euid != euid) { + rc = -EBADMSG; + printk(KERN_WARNING "%s: Received message from user " + "[%d]; expected message from user [%d]\n", __func__, + euid, ctx_euid); + goto unlock; + } + if (tsk_user_ns != user_ns) { + rc = -EBADMSG; + printk(KERN_WARNING "%s: Received message from user_ns " + "[0x%p]; expected message from user_ns [0x%p]\n", + __func__, user_ns, tsk_user_ns); + goto unlock; + } + if (daemon->pid != pid) { + rc = -EBADMSG; + printk(KERN_ERR "%s: User [%d] sent a message response " + "from an unrecognized process [0x%p]\n", + __func__, ctx_euid, pid); + goto unlock; + } if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) { rc = -EINVAL; printk(KERN_WARNING "%s: Desired context element is not " @@ -259,8 +359,9 @@ int ecryptfs_process_response(struct ecryptfs_daemon *daemon, } memcpy(msg_ctx->msg, msg, msg_size); msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE; - wake_up_process(msg_ctx->task); rc = 0; +wake_up: + wake_up_process(msg_ctx->task); unlock: mutex_unlock(&msg_ctx->mux); out: @@ -282,11 +383,14 @@ ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx) { struct ecryptfs_daemon *daemon; + uid_t euid = current_euid(); int rc; - rc = ecryptfs_find_daemon_by_euid(&daemon); + rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); if (rc || !daemon) { rc = -ENOTCONN; + printk(KERN_ERR "%s: User [%d] does not have a daemon " + "registered\n", __func__, euid); goto out; } mutex_lock(&ecryptfs_msg_ctx_lists_mux); diff --git a/trunk/fs/ecryptfs/miscdev.c b/trunk/fs/ecryptfs/miscdev.c index 412e6eda25f8..c0038f6566d4 100644 --- a/trunk/fs/ecryptfs/miscdev.c +++ b/trunk/fs/ecryptfs/miscdev.c @@ -33,7 +33,7 @@ static atomic_t ecryptfs_num_miscdev_opens; /** * ecryptfs_miscdev_poll - * @file: dev file + * @file: dev file (ignored) * @pt: dev poll table (ignored) * * Returns the poll mask @@ -41,10 +41,20 @@ static atomic_t ecryptfs_num_miscdev_opens; static unsigned int ecryptfs_miscdev_poll(struct file *file, poll_table *pt) { - struct ecryptfs_daemon *daemon = file->private_data; + struct ecryptfs_daemon *daemon; unsigned int mask = 0; + uid_t euid = current_euid(); + int rc; + mutex_lock(&ecryptfs_daemon_hash_mux); + /* TODO: Just use file->private_data? */ + rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); + if (rc || !daemon) { + mutex_unlock(&ecryptfs_daemon_hash_mux); + return -EINVAL; + } mutex_lock(&daemon->mux); + mutex_unlock(&ecryptfs_daemon_hash_mux); if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { printk(KERN_WARNING "%s: Attempt to poll on zombified " "daemon\n", __func__); @@ -69,7 +79,7 @@ ecryptfs_miscdev_poll(struct file *file, poll_table *pt) /** * ecryptfs_miscdev_open * @inode: inode of miscdev handle (ignored) - * @file: file for miscdev handle + * @file: file for miscdev handle (ignored) * * Returns zero on success; non-zero otherwise */ @@ -77,6 +87,7 @@ static int ecryptfs_miscdev_open(struct inode *inode, struct file *file) { struct ecryptfs_daemon *daemon = NULL; + uid_t euid = current_euid(); int rc; mutex_lock(&ecryptfs_daemon_hash_mux); @@ -87,20 +98,30 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file) "count; rc = [%d]\n", __func__, rc); goto out_unlock_daemon_list; } - rc = ecryptfs_find_daemon_by_euid(&daemon); - if (!rc) { - rc = -EINVAL; - goto out_unlock_daemon_list; - } - rc = ecryptfs_spawn_daemon(&daemon, file); - if (rc) { - printk(KERN_ERR "%s: Error attempting to spawn daemon; " - "rc = [%d]\n", __func__, rc); - goto out_module_put_unlock_daemon_list; + rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); + if (rc || !daemon) { + rc = ecryptfs_spawn_daemon(&daemon, euid, current_user_ns(), + task_pid(current)); + if (rc) { + printk(KERN_ERR "%s: Error attempting to spawn daemon; " + "rc = [%d]\n", __func__, rc); + goto out_module_put_unlock_daemon_list; + } } mutex_lock(&daemon->mux); + if (daemon->pid != task_pid(current)) { + rc = -EINVAL; + printk(KERN_ERR "%s: pid [0x%p] has registered with euid [%d], " + "but pid [0x%p] has attempted to open the handle " + "instead\n", __func__, daemon->pid, daemon->euid, + task_pid(current)); + goto out_unlock_daemon; + } if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) { rc = -EBUSY; + printk(KERN_ERR "%s: Miscellaneous device handle may only be " + "opened once per daemon; pid [0x%p] already has this " + "handle open\n", __func__, daemon->pid); goto out_unlock_daemon; } daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN; @@ -119,7 +140,7 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file) /** * ecryptfs_miscdev_release * @inode: inode of fs/ecryptfs/euid handle (ignored) - * @file: file for fs/ecryptfs/euid handle + * @file: file for fs/ecryptfs/euid handle (ignored) * * This keeps the daemon registered until the daemon sends another * ioctl to fs/ecryptfs/ctl or until the kernel module unregisters. @@ -129,18 +150,20 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file) static int ecryptfs_miscdev_release(struct inode *inode, struct file *file) { - struct ecryptfs_daemon *daemon = file->private_data; + struct ecryptfs_daemon *daemon = NULL; + uid_t euid = current_euid(); int rc; + mutex_lock(&ecryptfs_daemon_hash_mux); + rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); + if (rc || !daemon) + daemon = file->private_data; mutex_lock(&daemon->mux); BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN)); daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN; atomic_dec(&ecryptfs_num_miscdev_opens); mutex_unlock(&daemon->mux); - - mutex_lock(&ecryptfs_daemon_hash_mux); rc = ecryptfs_exorcise_daemon(daemon); - mutex_unlock(&ecryptfs_daemon_hash_mux); if (rc) { printk(KERN_CRIT "%s: Fatal error whilst attempting to " "shut down daemon; rc = [%d]. Please report this " @@ -148,6 +171,7 @@ ecryptfs_miscdev_release(struct inode *inode, struct file *file) BUG(); } module_put(THIS_MODULE); + mutex_unlock(&ecryptfs_daemon_hash_mux); return rc; } @@ -224,7 +248,7 @@ int ecryptfs_send_miscdev(char *data, size_t data_size, /** * ecryptfs_miscdev_read - format and send message from queue - * @file: miscdevfs handle + * @file: fs/ecryptfs/euid miscdevfs handle (ignored) * @buf: User buffer into which to copy the next message on the daemon queue * @count: Amount of space available in @buf * @ppos: Offset in file (ignored) @@ -238,27 +262,43 @@ static ssize_t ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct ecryptfs_daemon *daemon = file->private_data; + struct ecryptfs_daemon *daemon; struct ecryptfs_msg_ctx *msg_ctx; size_t packet_length_size; char packet_length[ECRYPTFS_MAX_PKT_LEN_SIZE]; size_t i; size_t total_length; + uid_t euid = current_euid(); int rc; + mutex_lock(&ecryptfs_daemon_hash_mux); + /* TODO: Just use file->private_data? */ + rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); + if (rc || !daemon) { + mutex_unlock(&ecryptfs_daemon_hash_mux); + return -EINVAL; + } mutex_lock(&daemon->mux); + if (task_pid(current) != daemon->pid) { + mutex_unlock(&daemon->mux); + mutex_unlock(&ecryptfs_daemon_hash_mux); + return -EPERM; + } if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { rc = 0; + mutex_unlock(&ecryptfs_daemon_hash_mux); printk(KERN_WARNING "%s: Attempt to read from zombified " "daemon\n", __func__); goto out_unlock_daemon; } if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) { rc = 0; + mutex_unlock(&ecryptfs_daemon_hash_mux); goto out_unlock_daemon; } /* This daemon will not go away so long as this flag is set */ daemon->flags |= ECRYPTFS_DAEMON_IN_READ; + mutex_unlock(&ecryptfs_daemon_hash_mux); check_list: if (list_empty(&daemon->msg_ctx_out_queue)) { mutex_unlock(&daemon->mux); @@ -342,12 +382,16 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count, * ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon * @data: Bytes comprising struct ecryptfs_message * @data_size: sizeof(struct ecryptfs_message) + data len + * @euid: Effective user id of miscdevess sending the miscdev response + * @user_ns: The namespace in which @euid applies + * @pid: Miscdevess id of miscdevess sending the miscdev response * @seq: Sequence number for miscdev response packet * * Returns zero on success; non-zero otherwise */ -static int ecryptfs_miscdev_response(struct ecryptfs_daemon *daemon, char *data, - size_t data_size, u32 seq) +static int ecryptfs_miscdev_response(char *data, size_t data_size, + uid_t euid, struct user_namespace *user_ns, + struct pid *pid, u32 seq) { struct ecryptfs_message *msg = (struct ecryptfs_message *)data; int rc; @@ -359,7 +403,7 @@ static int ecryptfs_miscdev_response(struct ecryptfs_daemon *daemon, char *data, rc = -EINVAL; goto out; } - rc = ecryptfs_process_response(daemon, msg, seq); + rc = ecryptfs_process_response(msg, euid, user_ns, pid, seq); if (rc) printk(KERN_ERR "Error processing response message; rc = [%d]\n", rc); @@ -369,7 +413,7 @@ static int ecryptfs_miscdev_response(struct ecryptfs_daemon *daemon, char *data, /** * ecryptfs_miscdev_write - handle write to daemon miscdev handle - * @file: File for misc dev handle + * @file: File for misc dev handle (ignored) * @buf: Buffer containing user data * @count: Amount of data in @buf * @ppos: Pointer to offset in file (ignored) @@ -384,6 +428,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf, u32 seq; size_t packet_size, packet_size_length; char *data; + uid_t euid = current_euid(); unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE]; ssize_t rc; @@ -443,9 +488,10 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf, } memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE); seq = be32_to_cpu(counter_nbo); - rc = ecryptfs_miscdev_response(file->private_data, + rc = ecryptfs_miscdev_response( &data[PKT_LEN_OFFSET + packet_size_length], - packet_size, seq); + packet_size, euid, current_user_ns(), + task_pid(current), seq); if (rc) { printk(KERN_WARNING "%s: Failed to deliver miscdev " "response to requesting operation; rc = [%zd]\n", diff --git a/trunk/fs/ecryptfs/mmap.c b/trunk/fs/ecryptfs/mmap.c index bd1d57f98f74..a46b3a8fee1e 100644 --- a/trunk/fs/ecryptfs/mmap.c +++ b/trunk/fs/ecryptfs/mmap.c @@ -66,6 +66,18 @@ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) { int rc; + /* + * Refuse to write the page out if we are called from reclaim context + * since our writepage() path may potentially allocate memory when + * calling into the lower fs vfs_write() which may in turn invoke + * us again. + */ + if (current->flags & PF_MEMALLOC) { + redirty_page_for_writepage(wbc, page); + rc = 0; + goto out; + } + rc = ecryptfs_encrypt_page(page); if (rc) { ecryptfs_printk(KERN_WARNING, "Error encrypting " @@ -486,6 +498,7 @@ static int ecryptfs_write_end(struct file *file, struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; int rc; + int need_unlock_page = 1; ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" "(page w/ index = [0x%.16lx], to = [%d])\n", index, to); @@ -506,26 +519,26 @@ static int ecryptfs_write_end(struct file *file, "zeros in page with index = [0x%.16lx]\n", index); goto out; } - rc = ecryptfs_encrypt_page(page); - if (rc) { - ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " - "index [0x%.16lx])\n", index); - goto out; - } + set_page_dirty(page); + unlock_page(page); + need_unlock_page = 0; if (pos + copied > i_size_read(ecryptfs_inode)) { i_size_write(ecryptfs_inode, pos + copied); ecryptfs_printk(KERN_DEBUG, "Expanded file size to " "[0x%.16llx]\n", (unsigned long long)i_size_read(ecryptfs_inode)); + balance_dirty_pages_ratelimited(mapping); + rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); + if (rc) { + printk(KERN_ERR "Error writing inode size to metadata; " + "rc = [%d]\n", rc); + goto out; + } } - rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); - if (rc) - printk(KERN_ERR "Error writing inode size to metadata; " - "rc = [%d]\n", rc); - else - rc = copied; + rc = copied; out: - unlock_page(page); + if (need_unlock_page) + unlock_page(page); page_cache_release(page); return rc; } diff --git a/trunk/mm/page_alloc.c b/trunk/mm/page_alloc.c index 009ac285fea7..889532b8e6c1 100644 --- a/trunk/mm/page_alloc.c +++ b/trunk/mm/page_alloc.c @@ -4511,7 +4511,7 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size, pg_data_t *pgdat = NODE_DATA(nid); /* pg_data_t should be reset to zero when it's allocated */ - WARN_ON(pgdat->nr_zones || pgdat->classzone_idx); + WARN_ON(pgdat->nr_zones || pgdat->node_start_pfn || pgdat->classzone_idx); pgdat->node_id = nid; pgdat->node_start_pfn = node_start_pfn;