diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/afs/proc.c | 4 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 40 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 14 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 22 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 158 | ||||
-rw-r--r-- | fs/cifs/dir.c | 59 | ||||
-rw-r--r-- | fs/cifs/file.c | 2 | ||||
-rw-r--r-- | fs/cifs/inode.c | 178 | ||||
-rw-r--r-- | fs/cifs/link.c | 323 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 2 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 126 | ||||
-rw-r--r-- | fs/cifs/xattr.c | 49 | ||||
-rw-r--r-- | fs/hfsplus/dir.c | 2 | ||||
-rw-r--r-- | fs/hfsplus/inode.c | 2 | ||||
-rw-r--r-- | fs/hfsplus/xattr.c | 60 | ||||
-rw-r--r-- | fs/hfsplus/xattr.h | 2 | ||||
-rw-r--r-- | fs/hpfs/alloc.c | 66 | ||||
-rw-r--r-- | fs/hpfs/buffer.c | 96 | ||||
-rw-r--r-- | fs/hpfs/hpfs_fn.h | 2 | ||||
-rw-r--r-- | fs/hpfs/super.c | 29 | ||||
-rw-r--r-- | fs/namei.c | 6 | ||||
-rw-r--r-- | fs/super.c | 3 |
22 files changed, 717 insertions, 528 deletions
diff --git a/fs/afs/proc.c b/fs/afs/proc.c index bddc5120ed4..24a905b076f 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c @@ -130,8 +130,8 @@ int afs_proc_init(void) if (!proc_afs) goto error_dir; - if (!proc_create("cells", 0, proc_afs, &afs_proc_cells_fops) || - !proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops)) + if (!proc_create("cells", 0644, proc_afs, &afs_proc_cells_fops) || + !proc_create("rootcell", 0644, proc_afs, &afs_proc_rootcell_fops)) goto error_tree; _leave(" = 0"); diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 51f5e0ee723..8f9b4f710d4 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -895,9 +895,10 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, int oplock = 0; unsigned int xid; int rc, create_options = 0; - __u16 fid; struct cifs_tcon *tcon; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); + struct cifs_fid fid; + struct cifs_open_parms oparms; if (IS_ERR(tlink)) return ERR_CAST(tlink); @@ -908,12 +909,19 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, if (backup_cred(cifs_sb)) create_options |= CREATE_OPEN_BACKUP_INTENT; - rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, - create_options, &fid, &oplock, NULL, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + oparms.tcon = tcon; + oparms.cifs_sb = cifs_sb; + oparms.desired_access = READ_CONTROL; + oparms.create_options = create_options; + oparms.disposition = FILE_OPEN; + oparms.path = path; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = CIFS_open(xid, &oparms, &oplock, NULL); if (!rc) { - rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); - CIFSSMBClose(xid, tcon, fid); + rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen); + CIFSSMBClose(xid, tcon, fid.netfid); } cifs_put_tlink(tlink); @@ -950,10 +958,11 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, int oplock = 0; unsigned int xid; int rc, access_flags, create_options = 0; - __u16 fid; struct cifs_tcon *tcon; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); + struct cifs_fid fid; + struct cifs_open_parms oparms; if (IS_ERR(tlink)) return PTR_ERR(tlink); @@ -969,18 +978,25 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, else access_flags = WRITE_DAC; - rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags, - create_options, &fid, &oplock, NULL, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + oparms.tcon = tcon; + oparms.cifs_sb = cifs_sb; + oparms.desired_access = access_flags; + oparms.create_options = create_options; + oparms.disposition = FILE_OPEN; + oparms.path = path; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = CIFS_open(xid, &oparms, &oplock, NULL); if (rc) { cifs_dbg(VFS, "Unable to open file to set ACL\n"); goto out; } - rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag); + rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag); cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc); - CIFSSMBClose(xid, tcon, fid); + CIFSSMBClose(xid, tcon, fid.netfid); out: free_xid(xid); cifs_put_tlink(tlink); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index f918a998a08..a245d1809ed 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -370,8 +370,12 @@ struct smb_version_operations { void (*new_lease_key)(struct cifs_fid *); int (*generate_signingkey)(struct cifs_ses *); int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *); - int (*query_mf_symlink)(const unsigned char *, char *, unsigned int *, - struct cifs_sb_info *, unsigned int); + int (*query_mf_symlink)(unsigned int, struct cifs_tcon *, + struct cifs_sb_info *, const unsigned char *, + char *, unsigned int *); + int (*create_mf_symlink)(unsigned int, struct cifs_tcon *, + struct cifs_sb_info *, const unsigned char *, + char *, unsigned int *); /* if we can do cache read operations */ bool (*is_read_op)(__u32); /* set oplock level for the inode */ @@ -385,6 +389,12 @@ struct smb_version_operations { struct cifsFileInfo *target_file, u64 src_off, u64 len, u64 dest_off); int (*validate_negotiate)(const unsigned int, struct cifs_tcon *); + ssize_t (*query_all_EAs)(const unsigned int, struct cifs_tcon *, + const unsigned char *, const unsigned char *, char *, + size_t, const struct nls_table *, int); + int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *, + const char *, const void *, const __u16, + const struct nls_table *, int); }; struct smb_version_values { diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 2c29db6a247..79e6e9a93a8 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -362,11 +362,8 @@ extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nls_codepage); extern int CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid); -extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, const int disposition, - const int access_flags, const int omode, - __u16 *netfid, int *pOplock, FILE_ALL_INFO *, - const struct nls_table *nls_codepage, int remap); +extern int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, + int *oplock, FILE_ALL_INFO *buf); extern int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const int disposition, const int access_flags, const int omode, @@ -476,8 +473,8 @@ extern int CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon, const int netfid, __u64 *pExtAttrBits, __u64 *pMask); extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb); -extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr); -extern int CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon, +extern bool couldbe_mf_symlink(const struct cifs_fattr *fattr); +extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, const unsigned char *path); @@ -496,7 +493,12 @@ void cifs_writev_complete(struct work_struct *work); struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete); void cifs_writedata_release(struct kref *refcount); -int open_query_close_cifs_symlink(const unsigned char *path, char *pbuf, - unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb, - unsigned int xid); +int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const unsigned char *path, char *pbuf, + unsigned int *pbytes_read); +int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const unsigned char *path, char *pbuf, + unsigned int *pbytes_written); #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index d707edb6b85..4d881c35eec 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1273,104 +1273,124 @@ OldOpenRetry: } int -CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, - const char *fileName, const int openDisposition, - const int access_flags, const int create_options, __u16 *netfid, - int *pOplock, FILE_ALL_INFO *pfile_info, - const struct nls_table *nls_codepage, int remap) +CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock, + FILE_ALL_INFO *buf) { int rc = -EACCES; - OPEN_REQ *pSMB = NULL; - OPEN_RSP *pSMBr = NULL; + OPEN_REQ *req = NULL; + OPEN_RSP *rsp = NULL; int bytes_returned; int name_len; __u16 count; + struct cifs_sb_info *cifs_sb = oparms->cifs_sb; + struct cifs_tcon *tcon = oparms->tcon; + int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; + const struct nls_table *nls = cifs_sb->local_nls; + int create_options = oparms->create_options; + int desired_access = oparms->desired_access; + int disposition = oparms->disposition; + const char *path = oparms->path; openRetry: - rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req, + (void **)&rsp); if (rc) return rc; - pSMB->AndXCommand = 0xFF; /* none */ + /* no commands go after this */ + req->AndXCommand = 0xFF; - if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - count = 1; /* account for one byte pad to word boundary */ - name_len = - cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1), - fileName, PATH_MAX, nls_codepage, remap); - name_len++; /* trailing null */ + if (req->hdr.Flags2 & SMBFLG2_UNICODE) { + /* account for one byte pad to word boundary */ + count = 1; + name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1), + path, PATH_MAX, nls, remap); + /* trailing null */ + name_len++; name_len *= 2; - pSMB->NameLength = cpu_to_le16(name_len); - } else { /* BB improve check for buffer overruns BB */ - count = 0; /* no pad */ - name_len = strnlen(fileName, PATH_MAX); - name_len++; /* trailing null */ - pSMB->NameLength = cpu_to_le16(name_len); - strncpy(pSMB->fileName, fileName, name_len); + req->NameLength = cpu_to_le16(name_len); + } else { + /* BB improve check for buffer overruns BB */ + /* no pad */ + count = 0; + name_len = strnlen(path, PATH_MAX); + /* trailing null */ + name_len++; + req->NameLength = cpu_to_le16(name_len); + strncpy(req->fileName, path, name_len); } - if (*pOplock & REQ_OPLOCK) - pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK); - else if (*pOplock & REQ_BATCHOPLOCK) - pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); - pSMB->DesiredAccess = cpu_to_le32(access_flags); - pSMB->AllocationSize = 0; - /* set file as system file if special file such - as fifo and server expecting SFU style and - no Unix extensions */ + + if (*oplock & REQ_OPLOCK) + req->OpenFlags = cpu_to_le32(REQ_OPLOCK); + else if (*oplock & REQ_BATCHOPLOCK) + req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); + + req->DesiredAccess = cpu_to_le32(desired_access); + req->AllocationSize = 0; + + /* + * Set file as system file if special file such as fifo and server + * expecting SFU style and no Unix extensions. + */ if (create_options & CREATE_OPTION_SPECIAL) - pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); + req->FileAttributes = cpu_to_le32(ATTR_SYSTEM); else - pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); + req->FileAttributes = cpu_to_le32(ATTR_NORMAL); - /* XP does not handle ATTR_POSIX_SEMANTICS */ - /* but it helps speed up case sensitive checks for other - servers such as Samba */ + /* + * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case + * sensitive checks for other servers such as Samba. + */ if (tcon->ses->capabilities & CAP_UNIX) - pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); + req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); if (create_options & CREATE_OPTION_READONLY) - pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY); + req->FileAttributes |= cpu_to_le32(ATTR_READONLY); + + req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); + req->CreateDisposition = cpu_to_le32(disposition); + req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); - pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); - pSMB->CreateDisposition = cpu_to_le32(openDisposition); - pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); /* BB Expirement with various impersonation levels and verify */ - pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); - pSMB->SecurityFlags = - SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY; + req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); + req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY; count += name_len; - inc_rfc1001_len(pSMB, count); + inc_rfc1001_len(req, count); - pSMB->ByteCount = cpu_to_le16(count); - /* long_op set to 1 to allow for oplock break timeouts */ - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *)pSMBr, &bytes_returned, 0); + req->ByteCount = cpu_to_le16(count); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req, + (struct smb_hdr *)rsp, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_opens); if (rc) { cifs_dbg(FYI, "Error in Open = %d\n", rc); - } else { - *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */ - *netfid = pSMBr->Fid; /* cifs fid stays in le */ - /* Let caller know file was created so we can set the mode. */ - /* Do we care about the CreateAction in any other cases? */ - if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) - *pOplock |= CIFS_CREATE_ACTION; - if (pfile_info) { - memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime, - 36 /* CreationTime to Attributes */); - /* the file_info buf is endian converted by caller */ - pfile_info->AllocationSize = pSMBr->AllocationSize; - pfile_info->EndOfFile = pSMBr->EndOfFile; - pfile_info->NumberOfLinks = cpu_to_le32(1); - pfile_info->DeletePending = 0; - } + cifs_buf_release(req); + if (rc == -EAGAIN) + goto openRetry; + return rc; } - cifs_buf_release(pSMB); - if (rc == -EAGAIN) - goto openRetry; + /* 1 byte no need to le_to_cpu */ + *oplock = rsp->OplockLevel; + /* cifs fid stays in le */ + oparms->fid->netfid = rsp->Fid; + + /* Let caller know file was created so we can set the mode. */ + /* Do we care about the CreateAction in any other cases? */ + if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction) + *oplock |= CIFS_CREATE_ACTION; + + if (buf) { + /* copy from CreationTime to Attributes */ + memcpy((char *)buf, (char *)&rsp->CreationTime, 36); + /* the file_info buf is endian converted by caller */ + buf->AllocationSize = rsp->AllocationSize; + buf->EndOfFile = rsp->EndOfFile; + buf->NumberOfLinks = cpu_to_le32(1); + buf->DeletePending = 0; + } + + cifs_buf_release(req); return rc; } diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index a514e0a65f6..d3a6796caa5 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -565,12 +565,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL; struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; - struct cifs_tcon *pTcon; + struct cifs_tcon *tcon; struct cifs_io_parms io_parms; char *full_path = NULL; struct inode *newinode = NULL; int oplock = 0; - u16 fileHandle; + struct cifs_fid fid; + struct cifs_open_parms oparms; FILE_ALL_INFO *buf = NULL; unsigned int bytes_written; struct win_dev *pdev; @@ -583,7 +584,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, if (IS_ERR(tlink)) return PTR_ERR(tlink); - pTcon = tlink_tcon(tlink); + tcon = tlink_tcon(tlink); xid = get_xid(); @@ -593,7 +594,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, goto mknod_out; } - if (pTcon->unix_ext) { + if (tcon->unix_ext) { struct cifs_unix_set_info_args args = { .mode = mode & ~current_umask(), .ctime = NO_CHANGE_64, @@ -608,7 +609,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, args.uid = INVALID_UID; /* no change */ args.gid = INVALID_GID; /* no change */ } - rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args, + rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -640,42 +641,44 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, if (backup_cred(cifs_sb)) create_options |= CREATE_OPEN_BACKUP_INTENT; - rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE, - GENERIC_WRITE, create_options, - &fileHandle, &oplock, buf, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + oparms.tcon = tcon; + oparms.cifs_sb = cifs_sb; + oparms.desired_access = GENERIC_WRITE; + oparms.create_options = create_options; + oparms.disposition = FILE_CREATE; + oparms.path = full_path; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = CIFS_open(xid, &oparms, &oplock, buf); if (rc) goto mknod_out; - /* BB Do not bother to decode buf since no local inode yet to put - * timestamps in, but we can reuse it safely */ + /* + * BB Do not bother to decode buf since no local inode yet to put + * timestamps in, but we can reuse it safely. + */ pdev = (struct win_dev *)buf; - io_parms.netfid = fileHandle; + io_parms.netfid = fid.netfid; io_parms.pid = current->tgid; - io_parms.tcon = pTcon; + io_parms.tcon = tcon; io_parms.offset = 0; io_parms.length = sizeof(struct win_dev); if (S_ISCHR(mode)) { memcpy(pdev->type, "IntxCHR", 8); - pdev->major = - cpu_to_le64(MAJOR(device_number)); - pdev->minor = - cpu_to_le64(MINOR(device_number)); - rc = CIFSSMBWrite(xid, &io_parms, - &bytes_written, (char *)pdev, - NULL, 0); + pdev->major = cpu_to_le64(MAJOR(device_number)); + pdev->minor = cpu_to_le64(MINOR(device_number)); + rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, + NULL, 0); } else if (S_ISBLK(mode)) { memcpy(pdev->type, "IntxBLK", 8); - pdev->major = - cpu_to_le64(MAJOR(device_number)); - pdev->minor = - cpu_to_le64(MINOR(device_number)); - rc = CIFSSMBWrite(xid, &io_parms, - &bytes_written, (char *)pdev, - NULL, 0); + pdev->major = cpu_to_le64(MAJOR(device_number)); + pdev->minor = cpu_to_le64(MINOR(device_number)); + rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, + NULL, 0); } /* else if (S_ISFIFO) */ - CIFSSMBClose(xid, pTcon, fileHandle); + CIFSSMBClose(xid, tcon, fid.netfid); d_drop(direntry); /* FIXME: add code here to set EAs */ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5a5a87240fe..853d6d1cc82 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -678,7 +678,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) /* * Can not refresh inode by passing in file_info buf to be returned by - * CIFSSMBOpen and then calling get_inode_info with returned buf since + * ops->open and then calling get_inode_info with returned buf since * file might have write behind data that needs to be flushed and server * version of file size can be stale. If we knew for sure that inode was * not dirty locally we could do this. diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 49719b8228e..9cb9679d735 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -383,10 +383,10 @@ int cifs_get_inode_info_unix(struct inode **pinode, /* check for Minshall+French symlinks */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { - int tmprc = CIFSCheckMFSymlink(xid, tcon, cifs_sb, &fattr, - full_path); + int tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, + full_path); if (tmprc) - cifs_dbg(FYI, "CIFSCheckMFSymlink: %d\n", tmprc); + cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); } if (*pinode == NULL) { @@ -404,18 +404,20 @@ int cifs_get_inode_info_unix(struct inode **pinode, } static int -cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, +cifs_sfu_type(struct cifs_fattr *fattr, const char *path, struct cifs_sb_info *cifs_sb, unsigned int xid) { int rc; int oplock = 0; - __u16 netfid; struct tcon_link *tlink; struct cifs_tcon *tcon; + struct cifs_fid fid; + struct cifs_open_parms oparms; struct cifs_io_parms io_parms; char buf[24]; unsigned int bytes_read; char *pbuf; + int buf_type = CIFS_NO_BUFFER; pbuf = buf; @@ -436,62 +438,69 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, return PTR_ERR(tlink); tcon = tlink_tcon(tlink); - rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ, - CREATE_NOT_DIR, &netfid, &oplock, NULL, - cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - if (rc == 0) { - int buf_type = CIFS_NO_BUFFER; - /* Read header */ - io_parms.netfid = netfid; - io_parms.pid = current->tgid; - io_parms.tcon = tcon; - io_parms.offset = 0; - io_parms.length = 24; - rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, - &buf_type); - if ((rc == 0) && (bytes_read >= 8)) { - if (memcmp("IntxBLK", pbuf, 8) == 0) { - cifs_dbg(FYI, "Block device\n"); - fattr->cf_mode |= S_IFBLK; - fattr->cf_dtype = DT_BLK; - if (bytes_read == 24) { - /* we have enough to decode dev num */ - __u64 mjr; /* major */ - __u64 mnr; /* minor */ - mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); - mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); - fattr->cf_rdev = MKDEV(mjr, mnr); - } - } else if (memcmp("IntxCHR", pbuf, 8) == 0) { - cifs_dbg(FYI, "Char device\n"); - fattr->cf_mode |= S_IFCHR; - fattr->cf_dtype = DT_CHR; - if (bytes_read == 24) { - /* we have enough to decode dev num */ - __u64 mjr; /* major */ - __u64 mnr; /* minor */ - mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); - mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); - fattr->cf_rdev = MKDEV(mjr, mnr); - } - } else if (memcmp("IntxLNK", pbuf, 7) == 0) { - cifs_dbg(FYI, "Symlink\n"); - fattr->cf_mode |= S_IFLNK; - fattr->cf_dtype = DT_LNK; - } else { - fattr->cf_mode |= S_IFREG; /* file? */ - fattr->cf_dtype = DT_REG; - rc = -EOPNOTSUPP; + oparms.tcon = tcon; + oparms.cifs_sb = cifs_sb; + oparms.desired_access = GENERIC_READ; + oparms.create_options = CREATE_NOT_DIR; + oparms.disposition = FILE_OPEN; + oparms.path = path; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = CIFS_open(xid, &oparms, &oplock, NULL); + if (rc) { + cifs_put_tlink(tlink); + return rc; + } + + /* Read header */ + io_parms.netfid = fid.netfid; + io_parms.pid = current->tgid; + io_parms.tcon = tcon; + io_parms.offset = 0; + io_parms.length = 24; + + rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); + if ((rc == 0) && (bytes_read >= 8)) { + if (memcmp("IntxBLK", pbuf, 8) == 0) { + cifs_dbg(FYI, "Block device\n"); + fattr->cf_mode |= S_IFBLK; + fattr->cf_dtype = DT_BLK; + if (bytes_read == 24) { + /* we have enough to decode dev num */ + __u64 mjr; /* major */ + __u64 mnr; /* minor */ + mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); + mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); + fattr->cf_rdev = MKDEV(mjr, mnr); } + } else if (memcmp("IntxCHR", pbuf, 8) == 0) { + cifs_dbg(FYI, "Char device\n"); + fattr->cf_mode |= S_IFCHR; + fattr->cf_dtype = DT_CHR; + if (bytes_read == 24) { + /* we have enough to decode dev num */ + __u64 mjr; /* major */ + __u64 mnr; /* minor */ + mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); + mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); + fattr->cf_rdev = MKDEV(mjr, mnr); + } + } else if (memcmp("IntxLNK", pbuf, 7) == 0) { + cifs_dbg(FYI, "Symlink\n"); + fattr->cf_mode |= S_IFLNK; + fattr->cf_dtype = DT_LNK; } else { - fattr->cf_mode |= S_IFREG; /* then it is a file */ + fattr->cf_mode |= S_IFREG; /* file? */ fattr->cf_dtype = DT_REG; - rc = -EOPNOTSUPP; /* or some unknown SFU type */ + rc = -EOPNOTSUPP; } - CIFSSMBClose(xid, tcon, netfid); + } else { + fattr->cf_mode |= S_IFREG; /* then it is a file */ + fattr->cf_dtype = DT_REG; + rc = -EOPNOTSUPP; /* or some unknown SFU type */ } + CIFSSMBClose(xid, tcon, fid.netfid); cifs_put_tlink(tlink); return rc; } @@ -800,10 +809,10 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, /* check for Minshall+French symlinks */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { - tmprc = CIFSCheckMFSymlink(xid, tcon, cifs_sb, &fattr, - full_path); + tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, + full_path); if (tmprc) - cifs_dbg(FYI, "CIFSCheckMFSymlink: %d\n", tmprc); + cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); } if (!*inode) { @@ -1032,7 +1041,8 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, { int oplock = 0; int rc; - __u16 netfid; + struct cifs_fid fid; + struct cifs_open_parms oparms; struct inode *inode = dentry->d_inode; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); @@ -1055,10 +1065,16 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, goto out; } - rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, - DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, - &netfid, &oplock, NULL, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + oparms.tcon = tcon; + oparms.cifs_sb = cifs_sb; + oparms.desired_access = DELETE | FILE_WRITE_ATTRIBUTES; + oparms.create_options = CREATE_NOT_DIR; + oparms.disposition = FILE_OPEN; + oparms.path = full_path; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = CIFS_open(xid, &oparms, &oplock, NULL); if (rc != 0) goto out; @@ -1079,7 +1095,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, goto out_close; } info_buf->Attributes = cpu_to_le32(dosattr); - rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, + rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid, current->tgid); /* although we would like to mark the file hidden if that fails we will still try to rename it */ @@ -1090,7 +1106,8 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, } /* rename the file */ - rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls, + rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc != 0) { @@ -1100,7 +1117,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, /* try to set DELETE_ON_CLOSE */ if (!cifsInode->delete_pending) { - rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, + rc = CIFSSMBSetFileDisposition(xid, tcon, true, fid.netfid, current->tgid); /* * some samba versions return -ENOENT when we try to set the @@ -1120,7 +1137,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, } out_close: - CIFSSMBClose(xid, tcon, netfid); + CIFSSMBClose(xid, tcon, fid.netfid); out: kfree(info_buf); cifs_put_tlink(tlink); @@ -1132,13 +1149,13 @@ out: * them anyway. */ undo_rename: - CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name, + CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); undo_setattr: if (dosattr != origattr) { info_buf->Attributes = cpu_to_le32(origattr); - if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, + if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid, current->tgid)) cifsInode->cifsAttrs = origattr; } @@ -1549,7 +1566,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, struct tcon_link *tlink; struct cifs_tcon *tcon; struct TCP_Server_Info *server; - __u16 srcfid; + struct cifs_fid fid; + struct cifs_open_parms oparms; int oplock, rc; tlink = cifs_sb_tlink(cifs_sb); @@ -1576,17 +1594,23 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, if (to_dentry->d_parent != from_dentry->d_parent) goto do_rename_exit; + oparms.tcon = tcon; + oparms.cifs_sb = cifs_sb; /* open the file to be renamed -- we need DELETE perms */ - rc = CIFSSMBOpen(xid, tcon, from_path, FILE_OPEN, DELETE, - CREATE_NOT_DIR, &srcfid, &oplock, NULL, - cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + oparms.desired_access = DELETE; + oparms.create_options = CREATE_NOT_DIR; + oparms.disposition = FILE_OPEN; + oparms.path = from_path; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = CIFS_open(xid, &oparms, &oplock, NULL); if (rc == 0) { - rc = CIFSSMBRenameOpenFile(xid, tcon, srcfid, + rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, (const char *) to_dentry->d_name.name, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - CIFSSMBClose(xid, tcon, srcfid); + CIFSSMBClose(xid, tcon, fid.netfid); } do_rename_exit: cifs_put_tlink(tlink); diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 92aee08483a..264ece71bdb 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -29,6 +29,10 @@ #include "cifs_debug.h" #include "cifs_fs_sb.h" +/* + * M-F Symlink Functions - Begin + */ + #define CIFS_MF_SYMLINK_LEN_OFFSET (4+1) #define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1)) #define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1)) @@ -91,10 +95,8 @@ symlink_hash_err: } static int -CIFSParseMFSymlink(const u8 *buf, - unsigned int buf_len, - unsigned int *_link_len, - char **_link_str) +parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len, + char **_link_str) { int rc; unsigned int link_len; @@ -137,7 +139,7 @@ CIFSParseMFSymlink(const u8 *buf, } static int -CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str) +format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str) { int rc; unsigned int link_len; @@ -180,190 +182,94 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str) return 0; } +bool +couldbe_mf_symlink(const struct cifs_fattr *fattr) +{ + if (!S_ISREG(fattr->cf_mode)) + /* it's not a symlink */ + return false; + + if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE) + /* it's not a symlink */ + return false; + + return true; +} + static int -CIFSCreateMFSymLink(const unsigned int xid, struct cifs_tcon *tcon, - const char *fromName, const char *toName, - struct cifs_sb_info *cifs_sb) +create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, const char *fromName, + const char *toName) { int rc; - int oplock = 0; - int remap; - int create_options = CREATE_NOT_DIR; - __u16 netfid = 0; u8 *buf; unsigned int bytes_written = 0; - struct cifs_io_parms io_parms; - struct nls_table *nls_codepage; - - nls_codepage = cifs_sb->local_nls; - remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; - rc = CIFSFormatMFSymlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName); - if (rc != 0) { - kfree(buf); - return rc; - } - - if (backup_cred(cifs_sb)) - create_options |= CREATE_OPEN_BACKUP_INTENT; - - rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE, - create_options, &netfid, &oplock, NULL, - nls_codepage, remap); - if (rc != 0) { - kfree(buf); - return rc; - } - - io_parms.netfid = netfid; - io_parms.pid = current->tgid; - io_parms.tcon = tcon; - io_parms.offset = 0; - io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; + rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName); + if (rc) + goto out; - rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, buf, NULL, 0); - CIFSSMBClose(xid, tcon, netfid); - kfree(buf); - if (rc != 0) - return rc; + rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon, cifs_sb, + fromName, buf, &bytes_written); + if (rc) + goto out; if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE) - return -EIO; - - return 0; + rc = -EIO; +out: + kfree(buf); + return rc; } static int -CIFSQueryMFSymLink(const unsigned int xid, struct cifs_tcon *tcon, - const unsigned char *searchName, char **symlinkinfo, - const struct nls_table *nls_codepage, int remap) +query_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, const unsigned char *path, + char **symlinkinfo) { int rc; - int oplock = 0; - __u16 netfid = 0; - u8 *buf; - char *pbuf; - unsigned int bytes_read = 0; - int buf_type = CIFS_NO_BUFFER; + u8 *buf = NULL; unsigned int link_len = 0; - struct cifs_io_parms io_parms; - FILE_ALL_INFO file_info; - - rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ, - CREATE_NOT_DIR, &netfid, &oplock, &file_info, - nls_codepage, remap); - if (rc != 0) - return rc; - - if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { - CIFSSMBClose(xid, tcon, netfid); - /* it's not a symlink */ - return -EINVAL; - } + unsigned int bytes_read = 0; buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; - pbuf = buf; - io_parms.netfid = netfid; - io_parms.pid = current->tgid; - io_parms.tcon = tcon; - io_parms.offset = 0; - io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; - - rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); - CIFSSMBClose(xid, tcon, netfid); - if (rc != 0) { - kfree(buf); - return rc; - } - - rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, symlinkinfo); - kfree(buf); - if (rc != 0) - return rc; - - return 0; -} - -bool -CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr) -{ - if (!(fattr->cf_mode & S_IFREG)) - /* it's not a symlink */ - return false; - if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE) - /* it's not a symlink */ - return false; - - return true; -} - -int -open_query_close_cifs_symlink(const unsigned char *path, char *pbuf, - unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb, - unsigned int xid) -{ - int rc; - int oplock = 0; - __u16 netfid = 0; - struct tcon_link *tlink; - struct cifs_tcon *ptcon; - struct cifs_io_parms io_parms; - int buf_type = CIFS_NO_BUFFER; - FILE_ALL_INFO file_info; - - tlink = cifs_sb_tlink(cifs_sb); - if (IS_ERR(tlink)) - return PTR_ERR(tlink); - ptcon = tlink_tcon(tlink); + if (tcon->ses->server->ops->query_mf_symlink) + rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon, + cifs_sb, path, buf, &bytes_read); + else + rc = -ENOSYS; - rc = CIFSSMBOpen(xid, ptcon, path, FILE_OPEN, GENERIC_READ, - CREATE_NOT_DIR, &netfid, &oplock, &file_info, - cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - if (rc != 0) { - cifs_put_tlink(tlink); - return rc; - } + if (rc) + goto out; - if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { - CIFSSMBClose(xid, ptcon, netfid); - cifs_put_tlink(tlink); - /* it's not a symlink */ - return rc; + if (bytes_read == 0) { /* not a symlink */ + rc = -EINVAL; + goto out; } - io_parms.netfid = netfid; - io_parms.pid = current->tgid; - io_parms.tcon = ptcon; - io_parms.offset = 0; - io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; - - rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type); - CIFSSMBClose(xid, ptcon, netfid); - cifs_put_tlink(tlink); + rc = parse_mf_symlink(buf, bytes_read, &link_len, symlinkinfo); +out: + kfree(buf); return rc; } - int -CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, - const unsigned char *path) +check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, + const unsigned char *path) { int rc; u8 *buf = NULL; unsigned int link_len = 0; unsigned int bytes_read = 0; - if (!CIFSCouldBeMFSymlink(fattr)) + if (!couldbe_mf_symlink(fattr)) /* it's not a symlink */ return 0; @@ -372,8 +278,8 @@ CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon, return -ENOMEM; if (tcon->ses->server->ops->query_mf_symlink) - rc = tcon->ses->server->ops->query_mf_symlink(path, buf, - &bytes_read, cifs_sb, xid); + rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon, + cifs_sb, path, buf, &bytes_read); else rc = -ENOSYS; @@ -383,7 +289,7 @@ CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon, if (bytes_read == 0) /* not a symlink */ goto out; - rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL); + rc = parse_mf_symlink(buf, bytes_read, &link_len, NULL); if (rc == -EINVAL) { /* it's not a symlink */ rc = 0; @@ -403,6 +309,95 @@ out: return rc; } +/* + * SMB 1.0 Protocol specific functions + */ + +int +cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, const unsigned char *path, + char *pbuf, unsigned int *pbytes_read) +{ + int rc; + int oplock = 0; + struct cifs_fid fid; + struct cifs_open_parms oparms; + struct cifs_io_parms io_parms; + int buf_type = CIFS_NO_BUFFER; + FILE_ALL_INFO file_info; + + oparms.tcon = tcon; + oparms.cifs_sb = cifs_sb; + oparms.desired_access = GENERIC_READ; + oparms.create_options = CREATE_NOT_DIR; + oparms.disposition = FILE_OPEN; + oparms.path = path; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = CIFS_open(xid, &oparms, &oplock, &file_info); + if (rc) + return rc; + + if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) + /* it's not a symlink */ + goto out; + + io_parms.netfid = fid.netfid; + io_parms.pid = current->tgid; + io_parms.tcon = tcon; + io_parms.offset = 0; + io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; + + rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type); +out: + CIFSSMBClose(xid, tcon, fid.netfid); + return rc; +} + +int +cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, const unsigned char *path, + char *pbuf, unsigned int *pbytes_written) +{ + int rc; + int oplock = 0; + struct cifs_fid fid; + struct cifs_open_parms oparms; + struct cifs_io_parms io_parms; + int create_options = CREATE_NOT_DIR; + + if (backup_cred(cifs_sb)) + create_options |= CREATE_OPEN_BACKUP_INTENT; + + oparms.tcon = tcon; + oparms.cifs_sb = cifs_sb; + oparms.desired_access = GENERIC_WRITE; + oparms.create_options = create_options; + oparms.disposition = FILE_OPEN; + oparms.path = path; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = CIFS_open(xid, &oparms, &oplock, NULL); + if (rc) + return rc; + + io_parms.netfid = fid.netfid; + io_parms.pid = current->tgid; + io_parms.tcon = tcon; + io_parms.offset = 0; + io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; + + rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf, NULL, 0); + CIFSSMBClose(xid, tcon, fid.netfid); + return rc; +} + +/* + * M-F Symlink Functions - End + */ + int cifs_hardlink(struct dentry *old_file, struct inode *inode, struct dentry *direntry) @@ -438,8 +433,10 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, CIFS_MOUNT_MAP_SPECIAL_CHR); else { server = tcon->ses->server; - if (!server->ops->create_hardlink) - return -ENOSYS; + if (!server->ops->create_hardlink) { + rc = -ENOSYS; + goto cifs_hl_exit; + } rc = server->ops->create_hardlink(xid, tcon, from_name, to_name, cifs_sb); if ((rc == -EIO) || (rc == -EINVAL)) @@ -530,15 +527,10 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) * and fallback to UNIX Extensions Symlinks. */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) - rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path, - cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + rc = query_mf_symlink(xid, tcon, cifs_sb, full_path, + &target_path); - if ((rc != 0) && cap_unix(tcon->ses)) - rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, - cifs_sb->local_nls); - else if (rc != 0 && server->ops->query_symlink) + if (rc != 0 && server->ops->query_symlink) rc = server->ops->query_symlink(xid, tcon, full_path, &target_path, cifs_sb); @@ -587,8 +579,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) /* BB what if DFS and this volume is on different share? BB */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) - rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname, - cifs_sb); + rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); else if (pTcon->unix_ext) rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, cifs_sb->local_nls); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 5940ecabbe6..b15862e0f68 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -749,7 +749,7 @@ static int cifs_filldir(char *find_entry, struct file *file, } if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && - CIFSCouldBeMFSymlink(&fattr)) + couldbe_mf_symlink(&fattr)) /* * trying to get the type and mode can be slow, * so just call those regular files for now, and mark diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 5f5ba0dc2ee..9ac5bfc9cc5 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -560,17 +560,24 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, if (!rc && (le32_to_cpu(data->Attributes) & ATTR_REPARSE)) { int tmprc; int oplock = 0; - __u16 netfid; + struct cifs_fid fid; + struct cifs_open_parms oparms; + + oparms.tcon = tcon; + oparms.cifs_sb = cifs_sb; + oparms.desired_access = FILE_READ_ATTRIBUTES; + oparms.create_options = 0; + oparms.disposition = FILE_OPEN; + oparms.path = full_path; + oparms.fid = &fid; + oparms.reconnect = false; /* Need to check if this is a symbolic link or not */ - tmprc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, - FILE_READ_ATTRIBUTES, 0, &netfid, &oplock, - NULL, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + tmprc = CIFS_open(xid, &oparms, &oplock, NULL); if (tmprc == -EOPNOTSUPP) *symlink = true; else - CIFSSMBClose(xid, tcon, netfid); + CIFSSMBClose(xid, tcon, fid.netfid); } return rc; @@ -705,12 +712,7 @@ cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms, oparms->cifs_sb->local_nls, oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - return CIFSSMBOpen(xid, oparms->tcon, oparms->path, - oparms->disposition, oparms->desired_access, - oparms->create_options, &oparms->fid->netfid, oplock, - buf, oparms->cifs_sb->local_nls, - oparms->cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + return CIFS_open(xid, oparms, oplock, buf); } static void @@ -761,8 +763,9 @@ smb_set_file_info(struct inode *inode, const char *full_path, { int oplock = 0; int rc; - __u16 netfid; __u32 netpid; + struct cifs_fid fid; + struct cifs_open_parms oparms; struct cifsFileInfo *open_file; struct cifsInodeInfo *cinode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); @@ -772,7 +775,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, /* if the file is already open for write, just use that fileid */ open_file = find_writable_file(cinode, true); if (open_file) { - netfid = open_file->fid.netfid; + fid.netfid = open_file->fid.netfid; netpid = open_file->pid; tcon = tlink_tcon(open_file->tlink); goto set_via_filehandle; @@ -796,12 +799,17 @@ smb_set_file_info(struct inode *inode, const char *full_path, goto out; } - cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n"); - rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, - SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, - &netfid, &oplock, NULL, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + oparms.tcon = tcon; + oparms.cifs_sb = cifs_sb; + oparms.desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES; + oparms.create_options = CREATE_NOT_DIR; + oparms.disposition = FILE_OPEN; + oparms.path = full_path; + oparms.fid = &fid; + oparms.reconnect = false; + cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n"); + rc = CIFS_open(xid, &oparms, &oplock, NULL); if (rc != 0) { if (rc == -EIO) rc = -EINVAL; @@ -811,12 +819,12 @@ smb_set_file_info(struct inode *inode, const char *full_path, netpid = current->tgid; set_via_filehandle: - rc = CIFSSMBSetFileInfo(xid, tcon, buf, netfid, netpid); + rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid); if (!rc) cinode->cifsAttrs = le32_to_cpu(buf->Attributes); if (open_file == NULL) - CIFSSMBClose(xid, tcon, netfid); + CIFSSMBClose(xid, tcon, fid.netfid); else cifsFileInfo_put(open_file); out: @@ -908,33 +916,80 @@ cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset, } static int +cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon, + const unsigned char *searchName, char **symlinkinfo, + const struct nls_table *nls_codepage) +{ +#ifdef CONFIG_CIFS_DFS_UPCALL + int rc; + unsigned int num_referrals = 0; + struct dfs_info3_param *referrals = NULL; + + rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, + &num_referrals, &referrals, 0); + + if (!rc && num_referrals > 0) { + *symlinkinfo = kstrndup(referrals->node_name, + strlen(referrals->node_name), + GFP_KERNEL); + if (!*symlinkinfo) + rc = -ENOMEM; + free_dfs_info_array(referrals, num_referrals); + } + return rc; +#else /* No DFS support */ + return -EREMOTE; +#endif +} + +static int cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, const char *full_path, char **target_path, struct cifs_sb_info *cifs_sb) { int rc; int oplock = 0; - __u16 netfid; + struct cifs_fid fid; + struct cifs_open_parms oparms; cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); - rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, - FILE_READ_ATTRIBUTES, OPEN_REPARSE_POINT, &netfid, - &oplock, NULL, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + /* Check for unix extensions */ + if (cap_unix(tcon->ses)) { + rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path, + cifs_sb->local_nls); + if (rc == -EREMOTE) + rc = cifs_unix_dfs_readlink(xid, tcon, full_path, + target_path, + cifs_sb->local_nls); + + goto out; + } + + oparms.tcon = tcon; + oparms.cifs_sb = cifs_sb; + oparms.desired_access = FILE_READ_ATTRIBUTES; + oparms.create_options = OPEN_REPARSE_POINT; + oparms.disposition = FILE_OPEN; + oparms.path = full_path; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = CIFS_open(xid, &oparms, &oplock, NULL); if (rc) - return rc; + goto out; - rc = CIFSSMBQuerySymLink(xid, tcon, netfid, target_path, + rc = CIFSSMBQuerySymLink(xid, tcon, fid.netfid, target_path, cifs_sb->local_nls); - if (rc) { - CIFSSMBClose(xid, tcon, netfid); - return rc; - } + if (rc) + goto out_close; convert_delimiter(*target_path, '/'); - CIFSSMBClose(xid, tcon, netfid); - cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); +out_close: + CIFSSMBClose(xid, tcon, fid.netfid); +out: + if (!rc) + cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); return rc; } @@ -1009,7 +1064,8 @@ struct smb_version_operations smb1_operations = { .mand_lock = cifs_mand_lock, .mand_unlock_range = cifs_unlock_range, .push_mand_locks = cifs_push_mandatory_locks, - .query_mf_symlink = open_query_close_cifs_symlink, + .query_mf_symlink = cifs_query_mf_symlink, + .create_mf_symlink = cifs_create_mf_symlink, .is_read_op = cifs_is_read_op, }; diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 09afda4cc58..95c43bb2033 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -82,9 +82,11 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) goto remove_ea_exit; ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ - rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL, - (__u16)0, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->set_EA) + rc = pTcon->ses->server->ops->set_EA(xid, pTcon, + full_path, ea_name, NULL, (__u16)0, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } remove_ea_exit: kfree(full_path); @@ -149,18 +151,22 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, cifs_dbg(FYI, "attempt to set cifs inode metadata\n"); ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ - rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, - (__u16)value_size, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->set_EA) + rc = pTcon->ses->server->ops->set_EA(xid, pTcon, + full_path, ea_name, ea_value, (__u16)value_size, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) goto set_ea_exit; ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ - rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, - (__u16)value_size, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->set_EA) + rc = pTcon->ses->server->ops->set_EA(xid, pTcon, + full_path, ea_name, ea_value, (__u16)value_size, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, strlen(CIFS_XATTR_CIFS_ACL)) == 0) { #ifdef CONFIG_CIFS_ACL @@ -272,17 +278,21 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, /* revalidate/getattr then populate from inode */ } /* BB add else when above is implemented */ ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ - rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, - buf_size, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->query_all_EAs) + rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, + full_path, ea_name, ea_value, buf_size, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) goto get_ea_exit; ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ - rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, - buf_size, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->query_all_EAs) + rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, + full_path, ea_name, ea_value, buf_size, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { #ifdef CONFIG_CIFS_POSIX @@ -400,11 +410,12 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) /* if proc/fs/cifs/streamstoxattr is set then search server for EAs or streams to returns as xattrs */ - rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data, - buf_size, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->server->ops->query_all_EAs) + rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, + full_path, NULL, data, buf_size, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); list_ea_exit: kfree(full_path); free_xid(xid); diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 9ee62985e73..bdec66522de 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -529,7 +529,7 @@ const struct inode_operations hfsplus_dir_inode_operations = { .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = hfsplus_listxattr, - .removexattr = hfsplus_removexattr, + .removexattr = generic_removexattr, #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL .get_acl = hfsplus_get_posix_acl, .set_acl = hfsplus_set_posix_acl, diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 4551cbd6bd4..fa929f325f8 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -331,7 +331,7 @@ static const struct inode_operations hfsplus_file_inode_operations = { .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = hfsplus_listxattr, - .removexattr = hfsplus_removexattr, + .removexattr = generic_removexattr, #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL .get_acl = hfsplus_get_posix_acl, .set_acl = hfsplus_set_posix_acl, diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index 0b4a5c9b93c..4e27edc082a 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -11,6 +11,8 @@ #include "xattr.h" #include "acl.h" +static int hfsplus_removexattr(struct inode *inode, const char *name); + const struct xattr_handler *hfsplus_xattr_handlers[] = { &hfsplus_xattr_osx_handler, &hfsplus_xattr_user_handler, @@ -274,14 +276,8 @@ int __hfsplus_setxattr(struct inode *inode, const char *name, HFSPLUS_IS_RSRC(inode)) return -EOPNOTSUPP; - if (strncmp(name, XATTR_MAC_OSX_PREFIX, - XATTR_MAC_OSX_PREFIX_LEN) == 0) - name += XATTR_MAC_OSX_PREFIX_LEN; - - if (value == NULL) { - value = ""; - size = 0; - } + if (value == NULL) + return hfsplus_removexattr(inode, name); err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); if (err) { @@ -399,16 +395,11 @@ end_setxattr: return err; } -static inline int is_osx_xattr(const char *xattr_name) -{ - return !is_known_namespace(xattr_name); -} - static int name_len(const char *xattr_name, int xattr_name_len) { int len = xattr_name_len + 1; - if (is_osx_xattr(xattr_name)) + if (!is_known_namespace(xattr_name)) len += XATTR_MAC_OSX_PREFIX_LEN; return len; @@ -419,7 +410,7 @@ static int copy_name(char *buffer, const char *xattr_name, int name_len) int len = name_len; int offset = 0; - if (is_osx_xattr(xattr_name)) { + if (!is_known_namespace(xattr_name)) { strncpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN); offset += XATTR_MAC_OSX_PREFIX_LEN; len += XATTR_MAC_OSX_PREFIX_LEN; @@ -497,18 +488,6 @@ ssize_t __hfsplus_getxattr(struct inode *inode, const char *name, HFSPLUS_IS_RSRC(inode)) return -EOPNOTSUPP; - if (strncmp(name, XATTR_MAC_OSX_PREFIX, - XATTR_MAC_OSX_PREFIX_LEN) == 0) { - /* skip "osx." prefix */ - name += XATTR_MAC_OSX_PREFIX_LEN; - /* - * Don't allow retrieving properly prefixed attributes - * by prepending them with "osx." - */ - if (is_known_namespace(name)) - return -EOPNOTSUPP; - } - if (!strcmp_xattr_finder_info(name)) return hfsplus_getxattr_finder_info(inode, value, size); @@ -743,28 +722,18 @@ end_listxattr: return res; } -int hfsplus_removexattr(struct dentry *dentry, const char *name) +static int hfsplus_removexattr(struct inode *inode, const char *name) { int err = 0; - struct inode *inode = dentry->d_inode; struct hfs_find_data cat_fd; u16 flags; u16 cat_entry_type; int is_xattr_acl_deleted = 0; int is_all_xattrs_deleted = 0; - if ((!S_ISREG(inode->i_mode) && - !S_ISDIR(inode->i_mode)) || - HFSPLUS_IS_RSRC(inode)) - return -EOPNOTSUPP; - if (!HFSPLUS_SB(inode->i_sb)->attr_tree) return -EOPNOTSUPP; - if (strncmp(name, XATTR_MAC_OSX_PREFIX, - XATTR_MAC_OSX_PREFIX_LEN) == 0) - name += XATTR_MAC_OSX_PREFIX_LEN; - if (!strcmp_xattr_finder_info(name)) return -EOPNOTSUPP; @@ -838,8 +807,12 @@ static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name, if (len > HFSPLUS_ATTR_MAX_STRLEN) return -EOPNOTSUPP; - strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); - strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); + /* + * Don't allow retrieving properly prefixed attributes + * by prepending them with "osx." + */ + if (is_known_namespace(name)) + return -EOPNOTSUPP; return hfsplus_getxattr(dentry, xattr_name, buffer, size); } @@ -857,12 +830,13 @@ static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name, if (len > HFSPLUS_ATTR_MAX_STRLEN) return -EOPNOTSUPP; + /* + * Don't allow setting properly prefixed attributes + * by prepending them with "osx." + */ if (is_known_namespace(name)) return -EOPNOTSUPP; - strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); - strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); - return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); } diff --git a/fs/hfsplus/xattr.h b/fs/hfsplus/xattr.h index 9e214490c31..288530cf80b 100644 --- a/fs/hfsplus/xattr.h +++ b/fs/hfsplus/xattr.h @@ -40,8 +40,6 @@ static inline ssize_t hfsplus_getxattr(struct dentry *dentry, ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); -int hfsplus_removexattr(struct dentry *dentry, const char *name); - int hfsplus_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr); diff --git a/fs/hpfs/alloc.c b/fs/hpfs/alloc.c index cdb84a83806..58b5106186d 100644 --- a/fs/hpfs/alloc.c +++ b/fs/hpfs/alloc.c @@ -8,6 +8,58 @@ #include "hpfs_fn.h" +static void hpfs_claim_alloc(struct super_block *s, secno sec) +{ + struct hpfs_sb_info *sbi = hpfs_sb(s); + if (sbi->sb_n_free != (unsigned)-1) { + if (unlikely(!sbi->sb_n_free)) { + hpfs_error(s, "free count underflow, allocating sector %08x", sec); + sbi->sb_n_free = -1; + return; + } + sbi->sb_n_free--; + } +} + +static void hpfs_claim_free(struct super_block *s, secno sec) +{ + struct hpfs_sb_info *sbi = hpfs_sb(s); + if (sbi->sb_n_free != (unsigned)-1) { + if (unlikely(sbi->sb_n_free >= sbi->sb_fs_size)) { + hpfs_error(s, "free count overflow, freeing sector %08x", sec); + sbi->sb_n_free = -1; + return; + } + sbi->sb_n_free++; + } +} + +static void hpfs_claim_dirband_alloc(struct super_block *s, secno sec) +{ + struct hpfs_sb_info *sbi = hpfs_sb(s); + if (sbi->sb_n_free_dnodes != (unsigned)-1) { + if (unlikely(!sbi->sb_n_free_dnodes)) { + hpfs_error(s, "dirband free count underflow, allocating sector %08x", sec); + sbi->sb_n_free_dnodes = -1; + return; + } + sbi->sb_n_free_dnodes--; + } +} + +static void hpfs_claim_dirband_free(struct super_block *s, secno sec) +{ + struct hpfs_sb_info *sbi = hpfs_sb(s); + if (sbi->sb_n_free_dnodes != (unsigned)-1) { + if (unlikely(sbi->sb_n_free_dnodes >= sbi->sb_dirband_size / 4)) { + hpfs_error(s, "dirband free count overflow, freeing sector %08x", sec); + sbi->sb_n_free_dnodes = -1; + return; + } + sbi->sb_n_free_dnodes++; + } +} + /* * Check if a sector is allocated in bitmap * This is really slow. Turned on only if chk==2 @@ -203,9 +255,15 @@ secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forwa } sec = 0; ret: + if (sec) { + i = 0; + do + hpfs_claim_alloc(s, sec + i); + while (unlikely(++i < n)); + } if (sec && f_p) { for (i = 0; i < forward; i++) { - if (!hpfs_alloc_if_possible(s, sec + i + 1)) { + if (!hpfs_alloc_if_possible(s, sec + n + i)) { hpfs_error(s, "Prealloc doesn't work! Wanted %d, allocated at %08x, can't allocate %d", forward, sec, i); sec = 0; break; @@ -228,6 +286,7 @@ static secno alloc_in_dirband(struct super_block *s, secno near) nr >>= 2; sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0); if (!sec) return 0; + hpfs_claim_dirband_alloc(s, sec); return ((sec & 0x3fff) << 2) + sbi->sb_dirband_start; } @@ -242,6 +301,7 @@ int hpfs_alloc_if_possible(struct super_block *s, secno sec) bmp[(sec & 0x3fff) >> 5] &= cpu_to_le32(~(1 << (sec & 0x1f))); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); + hpfs_claim_alloc(s, sec); return 1; } hpfs_brelse4(&qbh); @@ -275,6 +335,7 @@ void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n) return; } bmp[(sec & 0x3fff) >> 5] |= cpu_to_le32(1 << (sec & 0x1f)); + hpfs_claim_free(s, sec); if (!--n) { hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); @@ -359,6 +420,7 @@ void hpfs_free_dnode(struct super_block *s, dnode_secno dno) bmp[ssec >> 5] |= cpu_to_le32(1 << (ssec & 0x1f)); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); + hpfs_claim_dirband_free(s, dno); } } @@ -366,7 +428,7 @@ struct dnode *hpfs_alloc_dnode(struct super_block *s, secno near, dnode_secno *dno, struct quad_buffer_head *qbh) { struct dnode *d; - if (hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_dmap) > FREE_DNODES_ADD) { + if (hpfs_get_free_dnodes(s) > FREE_DNODES_ADD) { if (!(*dno = alloc_in_dirband(s, near))) if (!(*dno = hpfs_alloc_sector(s, near, 4, 0))) return NULL; } else { diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c index 4d0a1afa058..139ef1684d0 100644 --- a/fs/hpfs/buffer.c +++ b/fs/hpfs/buffer.c @@ -86,7 +86,6 @@ void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffer_head *qbh, int ahead) { - struct buffer_head *bh; char *data; hpfs_lock_assert(s); @@ -100,34 +99,32 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe hpfs_prefetch_sectors(s, secno, 4 + ahead); + if (!(qbh->bh[0] = sb_bread(s, secno + 0))) goto bail0; + if (!(qbh->bh[1] = sb_bread(s, secno + 1))) goto bail1; + if (!(qbh->bh[2] = sb_bread(s, secno + 2))) goto bail2; + if (!(qbh->bh[3] = sb_bread(s, secno + 3))) goto bail3; + + if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) && + likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) && + likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) { + return qbh->data = qbh->bh[0]->b_data; + } + qbh->data = data = kmalloc(2048, GFP_NOFS); if (!data) { printk("HPFS: hpfs_map_4sectors: out of memory\n"); - goto bail; + goto bail4; } - qbh->bh[0] = bh = sb_bread(s, secno); - if (!bh) - goto bail0; - memcpy(data, bh->b_data, 512); - - qbh->bh[1] = bh = sb_bread(s, secno + 1); - if (!bh) - goto bail1; - memcpy(data + 512, bh->b_data, 512); - - qbh->bh[2] = bh = sb_bread(s, secno + 2); - if (!bh) - goto bail2; - memcpy(data + 2 * 512, bh->b_data, 512); - - qbh->bh[3] = bh = sb_bread(s, secno + 3); - if (!bh) - goto bail3; - memcpy(data + 3 * 512, bh->b_data, 512); + memcpy(data + 0 * 512, qbh->bh[0]->b_data, 512); + memcpy(data + 1 * 512, qbh->bh[1]->b_data, 512); + memcpy(data + 2 * 512, qbh->bh[2]->b_data, 512); + memcpy(data + 3 * 512, qbh->bh[3]->b_data, 512); return data; + bail4: + brelse(qbh->bh[3]); bail3: brelse(qbh->bh[2]); bail2: @@ -135,9 +132,6 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe bail1: brelse(qbh->bh[0]); bail0: - kfree(data); - printk("HPFS: hpfs_map_4sectors: read error\n"); - bail: return NULL; } @@ -155,44 +149,54 @@ void *hpfs_get_4sectors(struct super_block *s, unsigned secno, return NULL; } - /*return hpfs_map_4sectors(s, secno, qbh, 0);*/ + if (!hpfs_get_sector(s, secno + 0, &qbh->bh[0])) goto bail0; + if (!hpfs_get_sector(s, secno + 1, &qbh->bh[1])) goto bail1; + if (!hpfs_get_sector(s, secno + 2, &qbh->bh[2])) goto bail2; + if (!hpfs_get_sector(s, secno + 3, &qbh->bh[3])) goto bail3; + + if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) && + likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) && + likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) { + return qbh->data = qbh->bh[0]->b_data; + } + if (!(qbh->data = kmalloc(2048, GFP_NOFS))) { printk("HPFS: hpfs_get_4sectors: out of memory\n"); - return NULL; + goto bail4; } - if (!(hpfs_get_sector(s, secno, &qbh->bh[0]))) goto bail0; - if (!(hpfs_get_sector(s, secno + 1, &qbh->bh[1]))) goto bail1; - if (!(hpfs_get_sector(s, secno + 2, &qbh->bh[2]))) goto bail2; - if (!(hpfs_get_sector(s, secno + 3, &qbh->bh[3]))) goto bail3; - memcpy(qbh->data, qbh->bh[0]->b_data, 512); - memcpy(qbh->data + 512, qbh->bh[1]->b_data, 512); - memcpy(qbh->data + 2*512, qbh->bh[2]->b_data, 512); - memcpy(qbh->data + 3*512, qbh->bh[3]->b_data, 512); return qbh->data; - bail3: brelse(qbh->bh[2]); - bail2: brelse(qbh->bh[1]); - bail1: brelse(qbh->bh[0]); - bail0: +bail4: + brelse(qbh->bh[3]); +bail3: + brelse(qbh->bh[2]); +bail2: + brelse(qbh->bh[1]); +bail1: + brelse(qbh->bh[0]); +bail0: return NULL; } void hpfs_brelse4(struct quad_buffer_head *qbh) { - brelse(qbh->bh[3]); - brelse(qbh->bh[2]); - brelse(qbh->bh[1]); + if (unlikely(qbh->data != qbh->bh[0]->b_data)) + kfree(qbh->data); brelse(qbh->bh[0]); - kfree(qbh->data); + brelse(qbh->bh[1]); + brelse(qbh->bh[2]); + brelse(qbh->bh[3]); } void hpfs_mark_4buffers_dirty(struct quad_buffer_head *qbh) { - memcpy(qbh->bh[0]->b_data, qbh->data, 512); - memcpy(qbh->bh[1]->b_data, qbh->data + 512, 512); - memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512); - memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512); + if (unlikely(qbh->data != qbh->bh[0]->b_data)) { + memcpy(qbh->bh[0]->b_data, qbh->data + 0 * 512, 512); + memcpy(qbh->bh[1]->b_data, qbh->data + 1 * 512, 512); + memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512); + memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512); + } mark_buffer_dirty(qbh->bh[0]); mark_buffer_dirty(qbh->bh[1]); mark_buffer_dirty(qbh->bh[2]); diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 6797bf80f6e..3ba49c080e4 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -312,7 +312,7 @@ static inline struct hpfs_sb_info *hpfs_sb(struct super_block *sb) __printf(2, 3) void hpfs_error(struct super_block *, const char *, ...); int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *); -unsigned hpfs_count_one_bitmap(struct super_block *, secno); +unsigned hpfs_get_free_dnodes(struct super_block *); /* * local time (HPFS) to GMT (Unix) diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index b8d01ef6f53..4534ff688b7 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -121,7 +121,7 @@ static void hpfs_put_super(struct super_block *s) call_rcu(&hpfs_sb(s)->rcu, lazy_free_sbi); } -unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) +static unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) { struct quad_buffer_head qbh; unsigned long *bits; @@ -129,7 +129,7 @@ unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) bits = hpfs_map_4sectors(s, secno, &qbh, 0); if (!bits) - return 0; + return (unsigned)-1; count = bitmap_weight(bits, 2048 * BITS_PER_BYTE); hpfs_brelse4(&qbh); return count; @@ -144,30 +144,45 @@ static unsigned count_bitmaps(struct super_block *s) hpfs_prefetch_bitmap(s, n); } for (n = 0; n < n_bands; n++) { + unsigned c; hpfs_prefetch_bitmap(s, n + COUNT_RD_AHEAD); - count += hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n])); + c = hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n])); + if (c != (unsigned)-1) + count += c; } return count; } +unsigned hpfs_get_free_dnodes(struct super_block *s) +{ + struct hpfs_sb_info *sbi = hpfs_sb(s); + if (sbi->sb_n_free_dnodes == (unsigned)-1) { + unsigned c = hpfs_count_one_bitmap(s, sbi->sb_dmap); + if (c == (unsigned)-1) + return 0; + sbi->sb_n_free_dnodes = c; + } + return sbi->sb_n_free_dnodes; +} + static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *s = dentry->d_sb; struct hpfs_sb_info *sbi = hpfs_sb(s); u64 id = huge_encode_dev(s->s_bdev->bd_dev); + hpfs_lock(s); - /*if (sbi->sb_n_free == -1) {*/ + if (sbi->sb_n_free == (unsigned)-1) sbi->sb_n_free = count_bitmaps(s); - sbi->sb_n_free_dnodes = hpfs_count_one_bitmap(s, sbi->sb_dmap); - /*}*/ + buf->f_type = s->s_magic; buf->f_bsize = 512; buf->f_blocks = sbi->sb_fs_size; buf->f_bfree = sbi->sb_n_free; buf->f_bavail = sbi->sb_n_free; buf->f_files = sbi->sb_dirband_size / 4; - buf->f_ffree = sbi->sb_n_free_dnodes; + buf->f_ffree = hpfs_get_free_dnodes(s); buf->f_fsid.val[0] = (u32)id; buf->f_fsid.val[1] = (u32)(id >> 32); buf->f_namelen = 254; diff --git a/fs/namei.c b/fs/namei.c index bcb838e2e52..d580df2e680 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -209,7 +209,6 @@ getname(const char __user * filename) { return getname_flags(filename, 0, NULL); } -EXPORT_SYMBOL(getname); #ifdef CONFIG_AUDITSYSCALL void putname(struct filename *name) @@ -3927,10 +3926,13 @@ out_dput: done_path_create(&new_path, new_dentry); if (delegated_inode) { error = break_deleg_wait(&delegated_inode); - if (!error) + if (!error) { + path_put(&old_path); goto retry; + } } if (retry_estale(error, how)) { + path_put(&old_path); how |= LOOKUP_REVAL; goto retry; } diff --git a/fs/super.c b/fs/super.c index cecd780e0f4..80d5cf2ca76 100644 --- a/fs/super.c +++ b/fs/super.c @@ -703,7 +703,6 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) if (flags & MS_RDONLY) acct_auto_close(sb); shrink_dcache_sb(sb); - sync_filesystem(sb); remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY); @@ -720,6 +719,8 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) } } + sync_filesystem(sb); + if (sb->s_op->remount_fs) { retval = sb->s_op->remount_fs(sb, &flags, data); if (retval) { |