#include "osi_compat.h"
#include "osi_pagecopy.h"
-#ifndef HAVE_PAGEVEC_LRU_ADD_FILE
+#ifndef HAVE_LINUX_PAGEVEC_LRU_ADD_FILE
#define __pagevec_lru_add_file __pagevec_lru_add
#endif
#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);
-/* Some uses of BKL are perhaps not needed for bypass or memcache--
- * why don't we try it out? */
-extern struct afs_cacheOps afs_UfsCacheOps;
-
-static inline void
-afs_maybe_lock_kernel(void) {
- if(afs_cacheType == &afs_UfsCacheOps)
- lock_kernel();
-}
-
-static inline void
-afs_maybe_unlock_kernel(void) {
- if(afs_cacheType == &afs_UfsCacheOps)
- unlock_kernel();
-}
/* This function converts a positive error code from AFS into a negative
* code suitable for passing into the Linux VFS layer. It checks that the
{
struct vcache *avc = VTOAFS(FILE_INODE(fp));
struct vrequest treq;
- register struct dcache *tdc;
+ struct dcache *tdc;
int code;
int offset;
int dirpos;
cred_t *credp = crref();
struct afs_fakestat_state fakestat;
- afs_maybe_lock_kernel();
AFS_GLOCK();
AFS_STATCNT(afs_readdir);
afs_PutFakeStat(&fakestat);
out1:
AFS_GUNLOCK();
- afs_maybe_unlock_kernel();
return code;
}
/* get a validated vcache entry */
code = afs_linux_VerifyVCache(vcp, NULL);
- /* Linux's Flushpage implementation doesn't use credp, so optimise
- * our code to not need to crref() it */
- osi_FlushPages(vcp, NULL); /* ensure stale pages are gone */
+ if (code == 0) {
+ /* Linux's Flushpage implementation doesn't use credp, so optimise
+ * our code to not need to crref() it */
+ osi_FlushPages(vcp, NULL); /* ensure stale pages are gone */
+ AFS_GUNLOCK();
+ code = generic_file_mmap(fp, vmap);
+ AFS_GLOCK();
+ if (!code)
+ vcp->f.states |= CMAPPED;
+ }
AFS_GUNLOCK();
- code = generic_file_mmap(fp, vmap);
- AFS_GLOCK();
- if (!code)
- vcp->f.states |= CMAPPED;
- AFS_GUNLOCK();
return code;
}
cred_t *credp = crref();
int code;
- afs_maybe_lock_kernel();
AFS_GLOCK();
code = afs_open(&vcp, fp->f_flags, credp);
AFS_GUNLOCK();
- afs_maybe_unlock_kernel();
crfree(credp);
return afs_convert_code(code);
cred_t *credp = crref();
int code = 0;
- afs_maybe_lock_kernel();
AFS_GLOCK();
code = afs_close(vcp, fp->f_flags, credp);
ObtainWriteLock(&vcp->lock, 807);
}
ReleaseWriteLock(&vcp->lock);
AFS_GUNLOCK();
- afs_maybe_unlock_kernel();
crfree(credp);
return afs_convert_code(code);
}
static int
+#if defined(FOP_FSYNC_TAKES_DENTRY)
afs_linux_fsync(struct file *fp, struct dentry *dp, int datasync)
+#else
+afs_linux_fsync(struct file *fp, int datasync)
+#endif
{
int code;
struct inode *ip = FILE_INODE(fp);
cred_t *credp = crref();
- afs_maybe_lock_kernel();
AFS_GLOCK();
code = afs_fsync(VTOAFS(ip), credp);
AFS_GUNLOCK();
- afs_maybe_unlock_kernel();
crfree(credp);
return afs_convert_code(code);
flock.l_pid = flp->fl_pid;
flock.l_whence = 0;
flock.l_start = flp->fl_start;
- flock.l_len = flp->fl_end - flp->fl_start + 1;
+ if (flp->fl_end == OFFSET_MAX)
+ flock.l_len = 0; /* Lock to end of file */
+ else
+ flock.l_len = flp->fl_end - flp->fl_start + 1;
/* Safe because there are no large files, yet */
#if defined(F_GETLK64) && (F_GETLK != F_GETLK64)
#endif /* F_GETLK64 && F_GETLK != F_GETLK64 */
AFS_GLOCK();
- code = afs_lockctl(vcp, &flock, cmd, credp);
+ code = afs_convert_code(afs_lockctl(vcp, &flock, cmd, credp));
AFS_GUNLOCK();
if ((code == 0 || flp->fl_type == F_UNLCK) &&
flp->fl_type = flock.l_type;
flp->fl_pid = flock.l_pid;
flp->fl_start = flock.l_start;
- flp->fl_end = flock.l_start + flock.l_len - 1;
+ if (flock.l_len == 0)
+ flp->fl_end = OFFSET_MAX; /* Lock to end of file */
+ else
+ flp->fl_end = flock.l_start + flock.l_len - 1;
crfree(credp);
- return afs_convert_code(code);
+ return code;
}
#ifdef STRUCT_FILE_OPERATIONS_HAS_FLOCK
flock.l_pid = flp->fl_pid;
flock.l_whence = 0;
flock.l_start = 0;
- flock.l_len = OFFSET_MAX;
+ flock.l_len = 0;
/* Safe because there are no large files, yet */
#if defined(F_GETLK64) && (F_GETLK != F_GETLK64)
#endif /* F_GETLK64 && F_GETLK != F_GETLK64 */
AFS_GLOCK();
- code = afs_lockctl(vcp, &flock, cmd, credp);
+ code = afs_convert_code(afs_lockctl(vcp, &flock, cmd, credp));
AFS_GUNLOCK();
if ((code == 0 || flp->fl_type == F_UNLCK) &&
flp->fl_pid = flock.l_pid;
crfree(credp);
- return afs_convert_code(code);
+ return code;
}
#endif
cred_t *credp;
int code;
#if defined(AFS_CACHE_BYPASS)
- int bypasscache;
+ int bypasscache = 0;
#endif
AFS_GLOCK();
if (code)
goto out;
#if defined(AFS_CACHE_BYPASS)
- /* If caching is bypassed for this file, or globally, just return 0 */
- if(cache_bypass_strategy == ALWAYS_BYPASS_CACHE)
- bypasscache = 1;
- else {
- ObtainReadLock(&vcp->lock);
- if(vcp->cachingStates & FCSBypass)
- bypasscache = 1;
- ReleaseReadLock(&vcp->lock);
- }
- if(bypasscache) {
- /* future proof: don't rely on 0 return from afs_InitReq */
- code = 0; goto out;
- }
+ /* If caching is bypassed for this file, or globally, just return 0 */
+ if (cache_bypass_strategy == ALWAYS_BYPASS_CACHE)
+ bypasscache = 1;
+ else {
+ ObtainReadLock(&vcp->lock);
+ if (vcp->cachingStates & FCSBypass)
+ bypasscache = 1;
+ ReleaseReadLock(&vcp->lock);
+ }
+ if (bypasscache) {
+ /* future proof: don't rely on 0 return from afs_InitReq */
+ code = 0;
+ goto out;
+ }
#endif
ObtainSharedLock(&vcp->lock, 535);
struct file_operations afs_file_fops = {
.read = afs_linux_read,
.write = afs_linux_write,
-#ifdef GENERIC_FILE_AIO_READ
+#ifdef HAVE_LINUX_GENERIC_FILE_AIO_READ
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
#endif
* AFS Linux dentry operations
**********************************************************************/
-/* check_bad_parent() : Checks if this dentry's vcache is a root vcache
+/* fix_bad_parent() : called if this dentry's vcache is a root vcache
* that has its mvid (parent dir's fid) pointer set to the wrong directory
- * due to being mounted in multiple points at once. If so, check_bad_parent()
+ * due to being mounted in multiple points at once. fix_bad_parent()
* calls afs_lookup() to correct the vcache's mvid, as well as the volume's
* dotdotfid and mtpoint fid members.
* Parameters:
* dp - dentry to be checked.
+ * credp - credentials
+ * vcp, pvc - item's and parent's vcache pointer
* Return Values:
* None.
* Sideeffects:
*/
static inline void
-check_bad_parent(struct dentry *dp)
+fix_bad_parent(struct dentry *dp, cred_t *credp, struct vcache *vcp, struct vcache *pvc)
{
- cred_t *credp;
- struct vcache *vcp = VTOAFS(dp->d_inode), *avc = NULL;
- struct vcache *pvc = VTOAFS(dp->d_parent->d_inode);
-
- if (vcp->mvid->Fid.Volume != pvc->f.fid.Fid.Volume) { /* bad parent */
- credp = crref();
-
- /* force a lookup, so vcp->mvid is fixed up */
- afs_lookup(pvc, (char *)dp->d_name.name, &avc, credp);
- if (!avc || vcp != avc) { /* bad, very bad.. */
- afs_Trace4(afs_iclSetp, CM_TRACE_TMP_1S3L, ICL_TYPE_STRING,
- "check_bad_parent: bad pointer returned from afs_lookup origvc newvc dentry",
- ICL_TYPE_POINTER, vcp, ICL_TYPE_POINTER, avc,
- ICL_TYPE_POINTER, dp);
- }
- if (avc)
- AFS_RELE(AFSTOV(avc));
- crfree(credp);
+ struct vcache *avc = NULL;
+
+ /* force a lookup, so vcp->mvid is fixed up */
+ afs_lookup(pvc, (char *)dp->d_name.name, &avc, credp);
+ if (!avc || vcp != avc) { /* bad, very bad.. */
+ afs_Trace4(afs_iclSetp, CM_TRACE_TMP_1S3L, ICL_TYPE_STRING,
+ "check_bad_parent: bad pointer returned from afs_lookup origvc newvc dentry",
+ ICL_TYPE_POINTER, vcp, ICL_TYPE_POINTER, avc,
+ ICL_TYPE_POINTER, dp);
}
+ if (avc)
+ AFS_RELE(AFSTOV(avc));
return;
}
if (afs_shuttingdown)
return EIO;
- afs_maybe_lock_kernel();
AFS_GLOCK();
#ifdef notyet
/* Make this a fast path (no crref), since it's called so often. */
- if (vcp->f.states & CStatd) {
-
- if (*dp->d_name.name != '/' && vcp->mvstat == 2) /* root vnode */
- check_bad_parent(dp); /* check and correct mvid */
+ if (vcp->states & CStatd) {
+ struct vcache *pvc = VTOAFS(dp->d_parent->d_inode);
- AFS_GUNLOCK();
- unlock_kernel();
+ if (*dp->d_name.name != '/' && vcp->mvstat == 2) { /* root vnode */
+ if (vcp->mvid->Fid.Volume != pvc->fid.Fid.Volume) { /* bad parent */
+ credp = crref();
+ AFS_GLOCK();
+ fix_bad_parent(dp); /* check and correct mvid */
+ AFS_GUNLOCK();
+ crfree(credp);
+ }
+ }
return 0;
}
#endif
code = afs_getattr(vcp, &vattr, credp);
crfree(credp);
}
+
if (!code)
afs_fill_inode(AFSTOV(vcp), &vattr);
AFS_GUNLOCK();
- afs_maybe_unlock_kernel();
return afs_convert_code(code);
}
* we are advised to follow the entry if it is a link or to make sure that
* it is a directory. But since the kernel itself checks these possibilities
* later on, we shouldn't have to do it until later. Perhaps in the future..
+ *
+ * The code here assumes that on entry the global lock is not held
*/
static int
#ifdef DOP_REVALIDATE_TAKES_NAMEIDATA
struct vattr vattr;
cred_t *credp = NULL;
struct vcache *vcp, *pvcp, *tvc = NULL;
+ struct dentry *parent;
int valid;
struct afs_fakestat_state fakestate;
+ int locked = 0;
- afs_maybe_lock_kernel();
- AFS_GLOCK();
afs_InitFakeStat(&fakestate);
if (dp->d_inode) {
-
+ parent = dget_parent(dp);
+ pvcp = VTOAFS(parent->d_inode);
vcp = VTOAFS(dp->d_inode);
- pvcp = VTOAFS(dp->d_parent->d_inode); /* dget_parent()? */
if (vcp == afs_globalVp)
goto good_dentry;
- if (vcp->mvstat == 1) { /* mount point */
+ if ((vcp->mvstat == 1) || (vcp->mvstat == 2)) { /* need to lock */
+ credp = crref();
+ AFS_GLOCK();
+ locked = 1;
+ }
+
+ if (locked && vcp->mvstat == 1) { /* mount point */
if (vcp->mvid && (vcp->f.states & CMValid)) {
int tryEvalOnly = 0;
int code = 0;
struct vrequest treq;
- credp = crref();
code = afs_InitReq(&treq, credp);
if (
(strcmp(dp->d_name.name, ".directory") == 0)) {
}
}
} else
- if (*dp->d_name.name != '/' && vcp->mvstat == 2) /* root vnode */
- check_bad_parent(dp); /* check and correct mvid */
+ if (locked && *dp->d_name.name != '/' && vcp->mvstat == 2) { /* root vnode */
+ if (vcp->mvid->Fid.Volume != pvcp->f.fid.Fid.Volume) { /* bad parent */
+ fix_bad_parent(dp, credp, vcp, pvcp); /* check and correct mvid */
+ }
+ }
#ifdef notdef
/* If the last looker changes, we should make sure the current
}
#endif
+
/* 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.
*/
- if (hgetlo(pvcp->f.m.DataVersion) > dp->d_time || !(vcp->f.states & CStatd)) {
-
+ if ((!locked) && (hgetlo(pvcp->f.m.DataVersion) > dp->d_time || !(vcp->f.states & CStatd)) ) {
credp = crref();
+ AFS_GLOCK();
+ locked = 1;
+ }
+
+ if (locked && (hgetlo(pvcp->f.m.DataVersion) > dp->d_time || !(vcp->f.states & CStatd))) {
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
/* Clean up */
if (tvc)
afs_PutVCache(tvc);
- afs_PutFakeStat(&fakestate);
- AFS_GUNLOCK();
+ afs_PutFakeStat(&fakestate); /* from here on vcp may be no longer valid */
+ if (locked) {
+ /* we hold the global lock if we evaluated a mount point */
+ AFS_GUNLOCK();
+ }
if (credp)
crfree(credp);
shrink_dcache_parent(dp);
d_drop(dp);
}
- afs_maybe_unlock_kernel();
return valid;
bad_dentry:
vattr.va_mode = mode;
vattr.va_type = mode & S_IFMT;
- afs_maybe_lock_kernel();
AFS_GLOCK();
code = afs_create(VTOAFS(dip), (char *)name, &vattr, NONEXCL, mode,
&vcp, credp);
}
AFS_GUNLOCK();
- afs_maybe_unlock_kernel();
crfree(credp);
return afs_convert_code(code);
}
struct dentry *newdp = NULL;
int code;
- afs_maybe_lock_kernel();
AFS_GLOCK();
code = afs_lookup(VTOAFS(dip), (char *)comp, &vcp, credp);
dput(alias);
} else {
iput(ip);
- afs_maybe_unlock_kernel();
crfree(credp);
return alias;
}
}
newdp = d_splice_alias(ip, dp);
- afs_maybe_unlock_kernel();
crfree(credp);
/* It's ok for the file to not be found. That's noted by the caller by
const char *name = dp->d_name.name;
struct vcache *tvc = VTOAFS(dp->d_inode);
- afs_maybe_lock_kernel();
-
if (VREFCOUNT(tvc) > 1 && tvc->opens > 0
&& !(tvc->f.states & CUnlinked)) {
d_drop(dp);
}
- afs_maybe_unlock_kernel();
crfree(credp);
return afs_convert_code(code);
}
struct vattr vattr;
const char *name = dp->d_name.name;
- afs_maybe_lock_kernel();
VATTR_NULL(&vattr);
vattr.va_mask = ATTR_MODE;
vattr.va_mode = mode;
}
AFS_GUNLOCK();
- afs_maybe_unlock_kernel();
crfree(credp);
return afs_convert_code(code);
}
struct dentry *rehash = NULL;
/* Prevent any new references during rename operation. */
- afs_maybe_lock_kernel();
if (!d_unhashed(newdp)) {
d_drop(newdp);
if (rehash)
d_rehash(rehash);
- afs_maybe_unlock_kernel();
-
crfree(credp);
return afs_convert_code(code);
}
setup_uio(auio, iovecp, (char *)address, offset, PAGE_SIZE, UIO_READ,
AFS_UIOSYS);
- afs_maybe_lock_kernel();
AFS_GLOCK();
AFS_DISCON_LOCK();
afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE, ICL_TYPE_POINTER, ip,
code);
AFS_DISCON_UNLOCK();
AFS_GUNLOCK();
- afs_maybe_unlock_kernel();
if (!code) {
/* XXX valid for no-cache also? Check last bits of files... :)
* Cognate code goes in afs_NoCacheFetchProc. */
page_cache_release(pp);
iovecp[page_ix].iov_base = (void *) 0;
base_index++;
- continue;
+ ancr->length -= PAGE_SIZE;
+ continue;
}
base_index++;
if(code) {
lock_page(pp);
}
+ /* increment page refcount--our original design assumed
+ * that locking it would effectively pin it; protect
+ * ourselves from the possiblity that this assumption is
+ * is faulty, at low cost (provided we do not fail to
+ * do the corresponding decref on the other side) */
+ get_page(pp);
+
/* save the page for background map */
iovecp[page_ix].iov_base = (void*) pp;
/* and put it on the LRU cache */
if (!pagevec_add(&lrupv, pp))
- __pagevec_lru_add(&lrupv);
+ __pagevec_lru_add_file(&lrupv);
}
}
/* If there were useful pages in the page list, make sure all pages
* are in the LRU cache, then schedule the read */
if(page_count) {
- pagevec_lru_add(&lrupv);
+ if (pagevec_count(&lrupv))
+ __pagevec_lru_add_file(&lrupv);
credp = crref();
code = afs_ReadNoCache(avc, ancr, credp);
crfree(credp);
struct nocache_read_request *ancr;
int code;
+ /*
+ * Special case: if page is at or past end of file, just zero it and set
+ * it as up to date.
+ */
+ if (page_offset(pp) >= i_size_read(fp->f_mapping->host)) {
+ zero_user_segment(pp, 0, PAGE_CACHE_SIZE);
+ SetPageUptodate(pp);
+ unlock_page(pp);
+ return 0;
+ }
+
ClearPageError(pp);
/* receiver frees */
PAGE_SIZE, UIO_READ, AFS_UIOSYS);
/* save the page for background map */
- /* XXX - Shouldn't we get a reference count here? */
+ get_page(pp); /* see above */
auio->uio_iov->iov_base = (void*) pp;
/* the background thread will free this */
ancr = osi_Alloc(sizeof(struct nocache_read_request));
ancr->length = PAGE_SIZE;
credp = crref();
- afs_maybe_lock_kernel();
code = afs_ReadNoCache(VTOAFS(FILE_INODE(fp)), ancr, credp);
- afs_maybe_unlock_kernel();
crfree(credp);
return afs_convert_code(code);
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();
buffer = kmap(pp) + offset;
base = page_offset(pp) + offset;
- afs_maybe_lock_kernel();
AFS_GLOCK();
afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp),
ICL_TYPE_INT32, code);
AFS_GUNLOCK();
- afs_maybe_unlock_kernel();
kunmap(pp);
return code;
credp = crref();
code = afs_linux_page_writeback(ip, pp, offset, count, credp);
- afs_maybe_lock_kernel();
AFS_GLOCK();
ObtainWriteLock(&vcp->lock, 533);
if (code > 0)
afs_linux_complete_writeback(vcp);
ReleaseWriteLock(&vcp->lock);
AFS_GUNLOCK();
- afs_maybe_unlock_kernel();
crfree(credp);
if (code1)
/* 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();
code = afs_linux_page_writeback(inode, pp, 0, to, credp);
- afs_maybe_lock_kernel();
AFS_GLOCK();
ObtainWriteLock(&vcp->lock, 538);
ReleaseWriteLock(&vcp->lock);
crfree(credp);
AFS_GUNLOCK();
- afs_maybe_unlock_kernel();
done:
end_page_writeback(pp);
return 0;
}
-#if defined(HAVE_WRITE_BEGIN)
+#if defined(STRUCT_ADDRESS_SPACE_OPERATIONS_HAS_WRITE_BEGIN)
static int
afs_linux_write_end(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied,
.readpage = afs_linux_readpage,
.readpages = afs_linux_readpages,
.writepage = afs_linux_writepage,
-#if defined (HAVE_WRITE_BEGIN)
+#if defined (STRUCT_ADDRESS_SPACE_OPERATIONS_HAS_WRITE_BEGIN)
.write_begin = afs_linux_write_begin,
.write_end = afs_linux_write_end,
#else
char *p = (char *)kmap(page);
int code;
- afs_maybe_lock_kernel();
AFS_GLOCK();
code = afs_linux_ireadlink(ip, p, PAGE_SIZE, AFS_UIOSYS);
AFS_GUNLOCK();
if (code < 0)
goto fail;
p[code] = '\0'; /* null terminate? */
- afs_maybe_unlock_kernel();
SetPageUptodate(page);
kunmap(page);
return 0;
fail:
- afs_maybe_unlock_kernel();
-
SetPageError(page);
kunmap(page);
unlock_page(page);
static struct inode_operations afs_symlink_iops = {
#if defined(USABLE_KERNEL_PAGE_SYMLINK_CACHE)
.readlink = page_readlink,
-# if defined(HAVE_KERNEL_PAGE_FOLLOW_LINK)
+# if defined(HAVE_LINUX_PAGE_FOLLOW_LINK)
.follow_link = page_follow_link,
# else
.follow_link = page_follow_link_light,
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;