#define MAX_ERRNO 1000L
#endif
-extern struct backing_dev_info afs_backing_dev_info;
+extern struct backing_dev_info *afs_backing_dev_info;
extern struct vcache *afs_globalVp;
extern int afs_notify_change(struct dentry *dp, struct iattr *iattrp);
*/
if (vcp->f.states & CStatd &&
(!afs_fakestat_enable || vcp->mvstat != 1) &&
- !afs_nfsexporter) {
+ !afs_nfsexporter &&
+ (vType(vcp) == VDIR || vType(vcp) == VLNK)) {
code = afs_CopyOutAttrs(vcp, &vattr);
} else {
credp = crref();
struct vattr vattr;
cred_t *credp = NULL;
struct vcache *vcp, *pvcp, *tvc = NULL;
+ struct dentry *parent;
int valid;
struct afs_fakestat_state fakestate;
afs_InitFakeStat(&fakestate);
if (dp->d_inode) {
-
vcp = VTOAFS(dp->d_inode);
- pvcp = VTOAFS(dp->d_parent->d_inode); /* dget_parent()? */
if (vcp == afs_globalVp)
goto good_dentry;
}
#endif
+ parent = dget_parent(dp);
+ pvcp = VTOAFS(parent->d_inode);
+
/* If the parent's DataVersion has changed or the vnode
* is longer valid, we need to do a full lookup. VerifyVCache
* isn't enough since the vnode may have been renamed.
credp = crref();
afs_lookup(pvcp, (char *)dp->d_name.name, &tvc, credp);
- if (!tvc || tvc != vcp)
+ if (!tvc || tvc != vcp) {
+ dput(parent);
goto bad_dentry;
+ }
- if (afs_getattr(vcp, &vattr, credp))
+ if (afs_getattr(vcp, &vattr, credp)) {
+ dput(parent);
goto bad_dentry;
+ }
vattr2inode(AFSTOV(vcp), &vattr);
dp->d_time = hgetlo(pvcp->f.m.DataVersion);
/* should we always update the attributes at this point? */
/* unlikely--the vcache entry hasn't changed */
+ dput(parent);
} else {
#ifdef notyet
- pvcp = VTOAFS(dp->d_parent->d_inode); /* dget_parent()? */
+ /* If this code is ever enabled, we should use dget_parent to handle
+ * getting the parent, and dput() to dispose of it. See above for an
+ * example ... */
+ pvcp = VTOAFS(dp->d_parent->d_inode);
if (hgetlo(pvcp->f.m.DataVersion) > dp->d_time)
goto bad_dentry;
#endif
return afs_convert_code(code);
}
+/* We have to have a Linux specific sillyrename function, because we
+ * also have to keep the dcache up to date when we're doing a silly
+ * rename - so we don't want the generic vnodeops doing this behind our
+ * back.
+ */
+
+static int
+afs_linux_sillyrename(struct inode *dir, struct dentry *dentry,
+ cred_t *credp)
+{
+ struct vcache *tvc = VTOAFS(dentry->d_inode);
+ struct dentry *__dp = NULL;
+ char *__name = NULL;
+ int code;
+
+ if (afs_linux_nfsfs_renamed(dentry))
+ return EBUSY;
+
+ do {
+ dput(__dp);
+
+ AFS_GLOCK();
+ if (__name)
+ osi_FreeSmallSpace(__name);
+ __name = afs_newname();
+ AFS_GUNLOCK();
+
+ __dp = lookup_one_len(__name, dentry->d_parent, strlen(__name));
+
+ if (IS_ERR(__dp)) {
+ osi_FreeSmallSpace(__name);
+ return EBUSY;
+ }
+ } while (__dp->d_inode != NULL);
+
+ AFS_GLOCK();
+ code = afs_rename(VTOAFS(dir), (char *)dentry->d_name.name,
+ VTOAFS(dir), (char *)__dp->d_name.name,
+ credp);
+ if (!code) {
+ tvc->mvid = (void *) __name;
+ crhold(credp);
+ if (tvc->uncred) {
+ crfree(tvc->uncred);
+ }
+ tvc->uncred = credp;
+ tvc->f.states |= CUnlinked;
+ afs_linux_set_nfsfs_renamed(dentry);
+ } else {
+ osi_FreeSmallSpace(__name);
+ }
+ AFS_GUNLOCK();
+
+ if (!code) {
+ __dp->d_time = hgetlo(VTOAFS(dir)->f.m.DataVersion);
+ d_move(dentry, __dp);
+ }
+ dput(__dp);
+
+ return code;
+}
+
+
static int
afs_linux_unlink(struct inode *dip, struct dentry *dp)
{
struct vcache *tvc = VTOAFS(dp->d_inode);
afs_maybe_lock_kernel();
+
if (VREFCOUNT(tvc) > 1 && tvc->opens > 0
&& !(tvc->f.states & CUnlinked)) {
- struct dentry *__dp;
- char *__name;
-
- __dp = NULL;
- __name = NULL;
- do {
- dput(__dp);
-
- AFS_GLOCK();
- if (__name)
- osi_FreeSmallSpace(__name);
- __name = afs_newname();
- AFS_GUNLOCK();
-
- __dp = lookup_one_len(__name, dp->d_parent, strlen(__name));
-
- if (IS_ERR(__dp))
- goto out;
- } while (__dp->d_inode != NULL);
+ code = afs_linux_sillyrename(dip, dp, credp);
+ } else {
AFS_GLOCK();
- code = afs_rename(VTOAFS(dip), (char *)dp->d_name.name, VTOAFS(dip), (char *)__dp->d_name.name, credp);
- if (!code) {
- tvc->mvid = (void *) __name;
- crhold(credp);
- if (tvc->uncred) {
- crfree(tvc->uncred);
- }
- tvc->uncred = credp;
- tvc->f.states |= CUnlinked;
- afs_linux_set_nfsfs_renamed(dp);
- } else {
- osi_FreeSmallSpace(__name);
- }
+ code = afs_remove(VTOAFS(dip), (char *)name, credp);
AFS_GUNLOCK();
-
- if (!code) {
- __dp->d_time = hgetlo(VTOAFS(dip)->f.m.DataVersion);
- d_move(dp, __dp);
- }
- dput(__dp);
-
- goto out;
+ if (!code)
+ d_drop(dp);
}
- AFS_GLOCK();
- code = afs_remove(VTOAFS(dip), (char *)name, credp);
- AFS_GUNLOCK();
- if (!code)
- d_drop(dp);
-out:
afs_maybe_unlock_kernel();
crfree(credp);
return afs_convert_code(code);
/* XXX - I suspect we should be locking the inodes before we use them! */
AFS_GUNLOCK();
- cacheFp = afs_linux_raw_open(&tdc->f.inode, NULL);
+ cacheFp = afs_linux_raw_open(&tdc->f.inode);
pagevec_init(&lrupv, 0);
code = afs_linux_read_cache(cacheFp, pp, tdc->f.chunk, &lrupv, NULL);
if (afs_linux_bypass_check(inode))
return afs_linux_bypass_readpages(fp, mapping, page_list, num_pages);
+ if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
+ return 0;
+
AFS_GLOCK();
if ((code = afs_linux_VerifyVCache(avc, NULL))) {
AFS_GUNLOCK();
}
AFS_GUNLOCK();
if (tdc)
- cacheFp = afs_linux_raw_open(&tdc->f.inode, NULL);
+ cacheFp = afs_linux_raw_open(&tdc->f.inode);
}
if (tdc && !add_to_page_cache(page, mapping, page->index,
/* Grab the creds structure currently held in the vnode, and
* get a reference to it, in case it goes away ... */
credp = vcp->cred;
- crhold(credp);
+ if (credp)
+ crhold(credp);
+ else
+ credp = crref();
ReleaseWriteLock(&vcp->lock);
AFS_GUNLOCK();
if (vattr)
vattr2inode(ip, vattr);
- ip->i_mapping->backing_dev_info = &afs_backing_dev_info;
+ ip->i_mapping->backing_dev_info = afs_backing_dev_info;
/* Reset ops if symlink or directory. */
if (S_ISREG(ip->i_mode)) {
ip->i_op = &afs_file_iops;