📄 brlock_tdb.c
字号:
} else { dbuf.dptr = (uint8_t *)locks; } locks[count] = lock; dbuf.dsize += sizeof(lock); status = rec->store(rec, dbuf, TDB_REPLACE); if (!NT_STATUS_IS_OK(status)) { goto fail; } talloc_free(rec); /* the caller needs to know if the real lock was granted. If we have reached here then it must be a pending lock that was granted, so tell them the lock failed */ if (lock_type >= PENDING_READ_LOCK) { return NT_STATUS_LOCK_NOT_GRANTED; } return NT_STATUS_OK; fail: talloc_free(rec); return status;}/* we are removing a lock that might be holding up a pending lock. Scan for pending locks that cover this range and if we find any then notify the server that it should retry the lock*/static void brl_tdb_notify_unlock(struct brl_context *brl, struct lock_struct *locks, int count, struct lock_struct *removed_lock){ int i, last_notice; /* the last_notice logic is to prevent stampeding on a lock range. It prevents us sending hundreds of notifies on the same range of bytes. It doesn't prevent all possible stampedes, but it does prevent the most common problem */ last_notice = -1; for (i=0;i<count;i++) { if (locks[i].lock_type >= PENDING_READ_LOCK && brl_tdb_overlap(&locks[i], removed_lock)) { if (last_notice != -1 && brl_tdb_overlap(&locks[i], &locks[last_notice])) { continue; } if (locks[i].lock_type == PENDING_WRITE_LOCK) { last_notice = i; } messaging_send_ptr(brl->messaging_ctx, locks[i].context.server, MSG_BRL_RETRY, locks[i].notify_ptr); } }}/* send notifications for all pending locks - the file is being closed by this user*/static void brl_tdb_notify_all(struct brl_context *brl, struct lock_struct *locks, int count){ int i; for (i=0;i<count;i++) { if (locks->lock_type >= PENDING_READ_LOCK) { brl_tdb_notify_unlock(brl, locks, count, &locks[i]); } }}/* Unlock a range of bytes.*/static NTSTATUS brl_tdb_unlock(struct brl_context *brl, struct brl_handle *brlh, uint16_t smbpid, uint64_t start, uint64_t size){ TDB_DATA kbuf, dbuf; int count, i; struct lock_struct *locks, *lock; struct lock_context context; NTSTATUS status; struct db_record *rec = NULL; kbuf.dptr = brlh->key.data; kbuf.dsize = brlh->key.length; rec = brl->db->fetch_locked(brl->db, brl, kbuf); if (rec == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } if (!rec->value.dptr) { talloc_free(rec); return NT_STATUS_RANGE_NOT_LOCKED; } dbuf = rec->value; context.smbpid = smbpid; context.server = brl->server; context.ctx = brl; /* there are existing locks - find a match */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { lock = &locks[i]; if (brl_tdb_same_context(&lock->context, &context) && lock->ntvfs == brlh->ntvfs && lock->start == start && lock->size == size && lock->lock_type == WRITE_LOCK) { break; } } if (i < count) goto found; for (i=0; i<count; i++) { lock = &locks[i]; if (brl_tdb_same_context(&lock->context, &context) && lock->ntvfs == brlh->ntvfs && lock->start == start && lock->size == size && lock->lock_type < PENDING_READ_LOCK) { break; } }found: if (i == count) { status = NT_STATUS_RANGE_NOT_LOCKED; } else if (count == 1) { status = rec->delete_rec(rec); } else { struct lock_struct removed_lock = *lock; if (i < count-1) { memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i)); } count--; /* send notifications for any relevant pending locks */ brl_tdb_notify_unlock(brl, locks, count, &removed_lock); dbuf.dsize = count * sizeof(*locks); status = rec->store(rec, dbuf, TDB_REPLACE); } talloc_free(rec); return status;}/* remove a pending lock. This is called when the caller has either given up trying to establish a lock or when they have succeeded in getting it. In either case they no longer need to be notified.*/static NTSTATUS brl_tdb_remove_pending(struct brl_context *brl, struct brl_handle *brlh, void *notify_ptr){ TDB_DATA kbuf, dbuf; int count, i; struct lock_struct *locks; NTSTATUS status; struct db_record *rec = NULL; kbuf.dptr = brlh->key.data; kbuf.dsize = brlh->key.length; rec = brl->db->fetch_locked(brl->db, brl, kbuf); if (rec == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } dbuf = rec->value; /* there are existing locks - find a match */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); status = NT_STATUS_RANGE_NOT_LOCKED; for (i=0; i<count; i++) { struct lock_struct *lock = &locks[i]; if (lock->lock_type >= PENDING_READ_LOCK && lock->notify_ptr == notify_ptr && cluster_id_equal(&lock->context.server, &brl->server)) { /* found it - delete it */ if (count == 1) { status = rec->delete_rec(rec); } else { if (i < count-1) { memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i)); } count--; dbuf.dsize = count * sizeof(*locks); status = rec->store(rec, dbuf, TDB_REPLACE); } break; } } talloc_free(rec); return status;}/* Test if we are allowed to perform IO on a region of an open file*/static NTSTATUS brl_tdb_locktest(struct brl_context *brl, struct brl_handle *brlh, uint16_t smbpid, uint64_t start, uint64_t size, enum brl_type lock_type){ TDB_DATA kbuf, dbuf; int count, i; struct lock_struct lock, *locks; NTSTATUS status; kbuf.dptr = brlh->key.data; kbuf.dsize = brlh->key.length; if (brl->db->fetch(brl->db, brl, kbuf, &dbuf) != 0) { return NT_STATUS_OK; } lock.context.smbpid = smbpid; lock.context.server = brl->server; lock.context.ctx = brl; lock.ntvfs = brlh->ntvfs; lock.start = start; lock.size = size; lock.lock_type = lock_type; /* there are existing locks - make sure they don't conflict */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); status = NT_STATUS_OK; for (i=0; i<count; i++) { if (brl_tdb_conflict_other(&locks[i], &lock)) { status = NT_STATUS_FILE_LOCK_CONFLICT; break; } } talloc_free(dbuf.dptr); return status;}/* Remove any locks associated with a open file.*/static NTSTATUS brl_tdb_close(struct brl_context *brl, struct brl_handle *brlh){ TDB_DATA kbuf, dbuf; int count, i, dcount=0; struct lock_struct *locks; NTSTATUS status; struct db_record *rec = NULL; kbuf.dptr = brlh->key.data; kbuf.dsize = brlh->key.length; rec = brl->db->fetch_locked(brl->db, brl, kbuf); if (rec == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } dbuf = rec->value; if (!dbuf.dptr) { talloc_free(rec); return NT_STATUS_OK; } /* there are existing locks - remove any for this fnum */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { struct lock_struct *lock = &locks[i]; if (lock->context.ctx == brl && cluster_id_equal(&lock->context.server, &brl->server) && lock->ntvfs == brlh->ntvfs) { /* found it - delete it */ if (count > 1 && i < count-1) { memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i)); } count--; i--; dcount++; } } status = NT_STATUS_OK; if (count == 0) { status = rec->delete_rec(rec); } else if (dcount != 0) { /* tell all pending lock holders for this file that they have a chance now. This is a bit indiscriminant, but works OK */ brl_tdb_notify_all(brl, locks, count); dbuf.dsize = count * sizeof(*locks); status = rec->store(rec, dbuf, TDB_REPLACE); } talloc_free(rec); return status;}static const struct brlock_ops brlock_tdb_ops = { .brl_init = brl_tdb_init, .brl_create_handle = brl_tdb_create_handle, .brl_lock = brl_tdb_lock, .brl_unlock = brl_tdb_unlock, .brl_remove_pending = brl_tdb_remove_pending, .brl_locktest = brl_tdb_locktest, .brl_close = brl_tdb_close};void brl_tdb_init_ops(void){ brl_set_ops(&brlock_tdb_ops);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -