/* * Copyright (c) 2002 Red Hat, Inc. All rights reserved. * * This software may be freely redistributed under the terms of the * GNU General Public License. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Authors: David Woodhouse <dwmw2@infradead.org> * David Howells <dhowells@redhat.com> *
*/
if (!vp->scb.have_cb) { /* it's a symlink we just created (the fileserver
* didn't give us a callback) */
afs_clear_cb_promise(vnode, afs_cb_promise_set_new_symlink);
} else {
vnode->cb_server = op->server;
afs_set_cb_promise(vnode, vp->scb.callback.expires_at,
afs_cb_promise_set_new_inode);
}
vnode->invalid_before = status->data_version; if (vnode->status.type == AFS_FTYPE_DIR)
afs_invalidate_dir(vnode, afs_dir_invalid_dv_mismatch); else
set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
change_size = true;
data_changed = true;
unexpected_jump = true;
} elseif (vnode->status.type == AFS_FTYPE_DIR) { /* Expected directory change is handled elsewhere so * that we can locally edit the directory and save on a * download.
*/ if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
data_changed = false;
change_size = true;
}
if (data_changed) {
inode_set_iversion_raw(inode, status->data_version);
/* Only update the size if the data version jumped. If the * file is being modified locally, then we might have our own * idea of what the size should be that's not the same as * what's on the server.
*/
vnode->netfs.remote_i_size = status->size; if (change_size || status->size > i_size_read(inode)) {
afs_set_i_size(vnode, status->size); if (unexpected_jump)
vnode->netfs.zero_point = status->size;
inode_set_ctime_to_ts(inode, t);
inode_set_atime_to_ts(inode, t);
} if (op->ops == &afs_fetch_data_operation)
op->fetch.subreq->rreq->i_size = status->size;
}
}
/* * Apply a callback to a vnode.
*/ staticvoid afs_apply_callback(struct afs_operation *op, struct afs_vnode_param *vp)
{ struct afs_callback *cb = &vp->scb.callback; struct afs_vnode *vnode = vp->vnode;
if (!afs_cb_is_broken(vp->cb_break_before, vnode)) { if (op->volume->type == AFSVL_RWVOL)
vnode->cb_server = op->server;
afs_set_cb_promise(vnode, cb->expires_at, afs_cb_promise_set_apply_cb);
}
}
/* * Apply the received status and callback to an inode all in the same critical * section to avoid races with afs_validate().
*/ void afs_vnode_commit_status(struct afs_operation *op, struct afs_vnode_param *vp)
{ struct afs_vnode *vnode = vp->vnode;
_enter("");
write_seqlock(&vnode->cb_lock);
if (vp->scb.have_error) { /* A YFS server will return this from RemoveFile2 and AFS and * YFS will return this from InlineBulkStatus.
*/ if (vp->scb.status.abort_code == VNOVNODE) {
set_bit(AFS_VNODE_DELETED, &vnode->flags);
clear_nlink(&vnode->netfs.inode);
__afs_break_callback(vnode, afs_cb_break_for_deleted);
op->flags &= ~AFS_OPERATION_DIR_CONFLICT;
}
} elseif (vp->scb.have_status) { if (vp->speculative &&
(test_bit(AFS_VNODE_MODIFYING, &vnode->flags) ||
vp->dv_before != vnode->status.data_version)) /* Ignore the result of a speculative bulk status fetch * if it splits around a modification op, thereby * appearing to regress the data version.
*/ goto out;
afs_apply_status(op, vp); if (vp->scb.have_cb)
afs_apply_callback(op, vp);
} elseif (vp->op_unlinked && !(op->flags & AFS_OPERATION_DIR_CONFLICT)) {
drop_nlink(&vnode->netfs.inode); if (vnode->netfs.inode.i_nlink == 0) {
set_bit(AFS_VNODE_DELETED, &vnode->flags);
__afs_break_callback(vnode, afs_cb_break_for_deleted);
}
}
out:
write_sequnlock(&vnode->cb_lock);
if (vp->scb.have_status)
afs_cache_permit(vnode, op->key, vp->cb_break_before, &vp->scb);
}
/* * Set up the root inode for a volume. This is always vnode 1, unique 1 within * the volume.
*/ struct inode *afs_root_iget(struct super_block *sb, struct key *key)
{ struct afs_super_info *as = AFS_FS_S(sb); struct afs_operation *op; struct afs_vnode *vnode; struct inode *inode; int ret;
if (vnode->volume &&
!(query_flags & AT_STATX_DONT_SYNC) &&
atomic64_read(&vnode->cb_expires_at) == AFS_NO_CB_PROMISE) {
key = afs_request_key(vnode->volume->cell); if (IS_ERR(key)) return PTR_ERR(key);
ret = afs_validate(vnode, key);
key_put(key); if (ret < 0) return ret;
}
do {
seq = read_seqbegin(&vnode->cb_lock);
generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); if (test_bit(AFS_VNODE_SILLY_DELETED, &vnode->flags) &&
stat->nlink > 0)
stat->nlink -= 1;
/* Lie about the size of directories. We maintain a locally * edited copy and may make different allocation decisions on * it, but we need to give userspace the server's size.
*/ if (S_ISDIR(inode->i_mode))
stat->size = vnode->netfs.remote_i_size;
} while (read_seqretry(&vnode->cb_lock, seq));
return 0;
}
/* * discard an AFS inode
*/ int afs_drop_inode(struct inode *inode)
{
_enter("");
if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags)) return generic_delete_inode(inode); else return generic_drop_inode(inode);
}
/* Wait for any outstanding writes to the server to complete */
loff_t from = min(size, i_size);
loff_t to = max(size, i_size);
ret = filemap_fdatawait_range(inode->i_mapping, from, to); if (ret < 0) goto out_unlock;
/* Don't talk to the server if we're just shortening in-memory * writes that haven't gone to the server yet.
*/ if (!(attr->ia_valid & (supported & ~ATTR_SIZE & ~ATTR_MTIME)) &&
attr->ia_size < i_size &&
attr->ia_size > vnode->netfs.remote_i_size) {
truncate_setsize(inode, attr->ia_size);
netfs_resize_file(&vnode->netfs, size, false);
fscache_resize_cookie(afs_vnode_cache(vnode),
attr->ia_size);
ret = 0; goto out_unlock;
}
}
op = afs_alloc_operation(((attr->ia_valid & ATTR_FILE) ?
afs_file_key(attr->ia_file) : NULL),
vnode->volume); if (IS_ERR(op)) {
ret = PTR_ERR(op); goto out_unlock;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.