int cifs_hardlink(struct dentry *old_file, struct inode *inode, struct dentry *direntry) { int rc = -EACCES; int xid; char *fromName = NULL; char *toName = NULL; struct cifs_sb_info *cifs_sb_target; struct cifsTconInfo *pTcon; struct cifsInodeInfo *cifsInode; xid = GetXid(); 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) */ fromName = build_path_from_dentry(old_file); toName = build_path_from_dentry(direntry); 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, cifs_sb_target->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); else { rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, cifs_sb_target->local_nls, cifs_sb_target->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if((rc == -EIO) || (rc == -EINVAL)) rc = -EOPNOTSUPP; } /* if (!rc) */ { /* renew_parental_timestamps(old_file); inode->i_nlink++; mark_inode_dirty(inode); d_instantiate(direntry, inode); */ /* BB add call to either mark inode dirty or refresh its data and timestamp to current time */ } d_drop(direntry); /* force new lookup from server */ cifsInode = CIFS_I(old_file->d_inode); cifsInode->time = 0; /* will force revalidate to go get info when needed */ cifs_hl_exit: kfree(fromName); kfree(toName); FreeXid(xid); return rc; }
int cifs_hardlink(struct dentry *old_file, struct inode *inode, struct dentry *direntry) { int rc = -EACCES; int xid; char *fromName = NULL; char *toName = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink; struct cifsTconInfo *pTcon; struct cifsInodeInfo *cifsInode; tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); pTcon = tlink_tcon(tlink); xid = GetXid(); fromName = build_path_from_dentry(old_file); toName = build_path_from_dentry(direntry); if ((fromName == NULL) || (toName == NULL)) { rc = -ENOMEM; goto cifs_hl_exit; } if (pTcon->unix_ext) rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); else { rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if ((rc == -EIO) || (rc == -EINVAL)) rc = -EOPNOTSUPP; } d_drop(direntry); /* force new lookup from server of target */ /* if source file is cached (oplocked) revalidate will not go to server until the file is closed or oplock broken so update nlinks locally */ if (old_file->d_inode) { cifsInode = CIFS_I(old_file->d_inode); if (rc == 0) { old_file->d_inode->i_nlink++; /* BB should we make this contingent on superblock flag NOATIME? */ /* old_file->d_inode->i_ctime = CURRENT_TIME;*/ /* parent dir timestamps will update from srv within a second, would it really be worth it to set the parent dir cifs inode time to zero to force revalidate (faster) for it too? */ } /* if not oplocked will force revalidate to get info on source file from srv */ cifsInode->time = 0; /* Will update parent dir timestamps from srv within a second. Would it really be worth it to set the parent dir (cifs inode) time field to zero to force revalidate on parent directory faster ie CIFS_I(inode)->time = 0; */ } cifs_hl_exit: kfree(fromName); kfree(toName); FreeXid(xid); cifs_put_tlink(tlink); return rc; }
int cifs_hardlink(struct dentry *old_file, struct inode *inode, struct dentry *direntry) { int rc = -EACCES; unsigned int xid; char *from_name = NULL; char *to_name = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink; struct cifs_tcon *tcon; struct TCP_Server_Info *server; struct cifsInodeInfo *cifsInode; tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); xid = get_xid(); from_name = build_path_from_dentry(old_file); to_name = build_path_from_dentry(direntry); if ((from_name == NULL) || (to_name == NULL)) { rc = -ENOMEM; goto cifs_hl_exit; } if (tcon->unix_ext) rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name, cifs_sb->local_nls, cifs_remap(cifs_sb)); else { server = tcon->ses->server; 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)) rc = -EOPNOTSUPP; } d_drop(direntry); /* force new lookup from server of target */ /* * if source file is cached (oplocked) revalidate will not go to server * until the file is closed or oplock broken so update nlinks locally */ if (d_really_is_positive(old_file)) { cifsInode = CIFS_I(d_inode(old_file)); if (rc == 0) { spin_lock(&d_inode(old_file)->i_lock); inc_nlink(d_inode(old_file)); spin_unlock(&d_inode(old_file)->i_lock); /* * parent dir timestamps will update from srv within a * second, would it really be worth it to set the parent * dir cifs inode time to zero to force revalidate * (faster) for it too? */ } /* * if not oplocked will force revalidate to get info on source * file from srv. Note Samba server prior to 4.2 has bug - * not updating src file ctime on hardlinks but Windows servers * handle it properly */ cifsInode->time = 0; /* * Will update parent dir timestamps from srv within a second. * Would it really be worth it to set the parent dir (cifs * inode) time field to zero to force revalidate on parent * directory faster ie * * CIFS_I(inode)->time = 0; */ } cifs_hl_exit: kfree(from_name); kfree(to_name); free_xid(xid); cifs_put_tlink(tlink); return rc; }
int cifs_hardlink(struct dentry *old_file, struct inode *inode, struct dentry *direntry) { int rc = -EACCES; int xid; char *fromName = NULL; char *toName = NULL; struct cifs_sb_info *cifs_sb_target; struct cifsTconInfo *pTcon; struct cifsInodeInfo *cifsInode; xid = GetXid(); 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) */ fromName = build_path_from_dentry(old_file); toName = build_path_from_dentry(direntry); 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, cifs_sb_target->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); else { rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, cifs_sb_target->local_nls, cifs_sb_target->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if((rc == -EIO) || (rc == -EINVAL)) rc = -EOPNOTSUPP; } d_drop(direntry); /* force new lookup from server of target */ /* if source file is cached (oplocked) revalidate will not go to server until the file is closed or oplock broken so update nlinks locally */ if(old_file->d_inode) { cifsInode = CIFS_I(old_file->d_inode); if(rc == 0) { old_file->d_inode->i_nlink++; old_file->d_inode->i_ctime = CURRENT_TIME; /* parent dir timestamps will update from srv within a second, would it really be worth it to set the parent dir cifs inode time to zero to force revalidate (faster) for it too? */ } /* if not oplocked will force revalidate to get info on source file from srv */ cifsInode->time = 0; /* Will update parent dir timestamps from srv within a second. Would it really be worth it to set the parent dir (cifs inode) time field to zero to force revalidate on parent directory faster ie CIFS_I(inode)->time = 0; */ } cifs_hl_exit: kfree(fromName); kfree(toName); FreeXid(xid); return rc; }