X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fcifs%2Flink.c;h=1455810ba1cbba4b6fdc0ddd95eb2cc67542382a;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=8deba2650f393e736a40b68098f57799223417d1;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 8deba2650..1455810ba 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -20,6 +20,7 @@ */ #include #include +#include #include "cifsfs.h" #include "cifspdu.h" #include "cifsglob.h" @@ -44,10 +45,18 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, cifs_sb_target = CIFS_SB(inode->i_sb); pTcon = cifs_sb_target->tcon; -/* No need to check for cross device links since server will do that - BB note DFS case in future though (when we may have to check) */ +/* No need to check for cross device links since server will do that + BB note DFS case in future though (when we may have to check) */ + down(&inode->i_sb->s_vfs_rename_sem); fromName = build_path_from_dentry(old_file); toName = build_path_from_dentry(direntry); + up(&inode->i_sb->s_vfs_rename_sem); + if((fromName == NULL) || (toName == NULL)) { + rc = -ENOMEM; + goto cifs_hl_exit; + } + if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX) rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, cifs_sb_target->local_nls); @@ -70,6 +79,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, cifsInode = CIFS_I(old_file->d_inode); cifsInode->time = 0; /* will force revalidate to go get info when needed */ +cifs_hl_exit: if (fromName) kfree(fromName); if (toName) @@ -85,24 +95,27 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) int rc = -EACCES; int xid; char *full_path = NULL; - char * target_path; + char * target_path = ERR_PTR(-ENOMEM); struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; xid = GetXid(); + + down(&direntry->d_sb->s_vfs_rename_sem); full_path = build_path_from_dentry(direntry); + up(&direntry->d_sb->s_vfs_rename_sem); + + if (!full_path) + goto out_no_free; + cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; target_path = kmalloc(PATH_MAX, GFP_KERNEL); - if(target_path == NULL) { - if (full_path) - kfree(full_path); - FreeXid(xid); - return -ENOMEM; + if (!target_path) { + target_path = ERR_PTR(-ENOMEM); + goto out; } - /* can not call the following line due to EFAULT in vfs_readlink which is presumably expecting a user space buffer */ - /* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1); */ /* BB add read reparse point symlink code and Unix extensions symlink code here BB */ if (pTcon->ses->capabilities & CAP_UNIX) @@ -113,25 +126,25 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) else { /* rc = CIFSSMBQueryReparseLinkInfo */ /* BB Add code to Query ReparsePoint info */ + /* BB Add MAC style xsymlink check here if enabled */ } - /* BB Anything else to do to handle recursive links? */ - /* BB Should we be using page symlink ops here? */ if (rc == 0) { /* BB Add special case check for Samba DFS symlinks */ target_path[PATH_MAX-1] = 0; - rc = vfs_follow_link(nd, target_path); + } else { + kfree(target_path); + target_path = ERR_PTR(rc); } - /* else EACCESS */ - if (target_path) - kfree(target_path); - if (full_path) - kfree(full_path); +out: + kfree(full_path); +out_no_free: FreeXid(xid); - return rc; + nd_set_link(nd, target_path); + return 0; } int @@ -149,7 +162,15 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; + down(&inode->i_sb->s_vfs_rename_sem); full_path = build_path_from_dentry(direntry); + up(&inode->i_sb->s_vfs_rename_sem); + + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + cFYI(1, ("Full path: %s ", full_path)); cFYI(1, ("symname is %s", symname)); @@ -163,10 +184,10 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) if (rc == 0) { if (pTcon->ses->capabilities & CAP_UNIX) rc = cifs_get_inode_info_unix(&newinode, full_path, - inode->i_sb); + inode->i_sb,xid); else rc = cifs_get_inode_info(&newinode, full_path, NULL, - inode->i_sb); + inode->i_sb,xid); if (rc != 0) { cFYI(1, @@ -185,7 +206,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) } int -cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) +cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) { struct inode *inode = direntry->d_inode; int rc = -EACCES; @@ -204,7 +225,18 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; + +/* BB would it be safe against deadlock to grab this sem + even though rename itself grabs the sem and calls lookup? */ +/* down(&inode->i_sb->s_vfs_rename_sem);*/ full_path = build_path_from_dentry(direntry); +/* up(&inode->i_sb->s_vfs_rename_sem);*/ + + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + cFYI(1, ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d", full_path, inode, pBuffer, buflen)); @@ -261,10 +293,7 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) if(referrals) kfree(referrals); kfree(tmp_path); - if(referrals) { - kfree(referrals); - } - } +} /* BB add code like else decode referrals then memcpy to tmpbuffer and free referrals string array BB */ } @@ -290,3 +319,10 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) FreeXid(xid); return rc; } + +void cifs_put_link(struct dentry *direntry, struct nameidata *nd) +{ + char *p = nd_get_link(nd); + if (!IS_ERR(p)) + kfree(p); +}