[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-cifs
Subject:    Re: [PATCH v3 1/5] CIFS: Move locks to cifsFileInfo structure
From:       Pavel Shilovsky <piastry () etersoft ! ru>
Date:       2012-03-30 12:03:03
Message-ID: CAKywueR96=jtjbSUM5BFZY56egFqCxZNCEY9Uc06C1FzUpszWw () mail ! gmail ! com
[Download RAW message or body]

29 อมาิม 2012šว. 23:13 ะฯฬฺุฯืมิลฬุ Jeff Layton <jlayton@redhat.com> ฮมะษำมฬ:
> On Tue, 27 Mar 2012 15:38:35 +0400
> Pavel Shilovsky <piastry@etersoft.ru> wrote:
> 
> > CIFS brlock cache can be used by several file handles if we have a
> > write-caching lease on the file that is supported by SMB2 protocol.
> > Prepate the code to handle this situation correctly by sorting brlocks
> > by a fid to easily push them in portions when lease break comes.
> > 
> > Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
> 
> I'm not sure I understand this. It seems like keeping them all as part
> of the inode would be simpler. How does it simplify things to put them
> in separate per-FID buckets?
> 
> I suppose one argument is that you could open the file twice and get 2
> separate FIDs and 2 separate leases, and have different locks against
> each. Then the server might recall one lease but not the other. In that
> case, you'd want to push out only the locks associated with that FID?
> 
> Is that the main concern, or am I missing the point here?

Two FIDS will have the same lease and when lease break comes they have
to push their locks to the server. To make this process faster we can
send a chunk of locks in one request, as we already do for cifs
mandatory locks. If we have all FID's lock in one place we don't need
to tun over the whole inode lock list to create groups when oplock
break comes.

The only difference between CIFS and SMB2 is that in SMB2 lock_element
structure in lock request doesn't contain pid element (that exists for
CIFS), assuming that all locks from the request associated with pid
from the header. So to handle this right we need further to replace
cifsFileInfo lock list (introduced by this patch) with "pid_lock" list

struct pid_lock {
  struct list_head lock_list;
  pid_t pid;
}

that group FID's locks by pid.

> 
> > ---
> > šfs/cifs/cifsfs.c š | š š1 -
> > šfs/cifs/cifsglob.h | š š3 +-
> > šfs/cifs/file.c š š | š 98 ++++++++++++++++++++++++++++++++--------------------
> > š3 files changed, 61 insertions(+), 41 deletions(-)
> > 
> > diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> > index eee522c..3ac61a7 100644
> > --- a/fs/cifs/cifsfs.c
> > +++ b/fs/cifs/cifsfs.c
> > @@ -939,7 +939,6 @@ cifs_init_once(void *inode)
> > š š š struct cifsInodeInfo *cifsi = inode;
> > 
> > š š š inode_init_once(&cifsi->vfs_inode);
> > - š š INIT_LIST_HEAD(&cifsi->llist);
> > š š š mutex_init(&cifsi->lock_mutex);
> > š}
> > 
> > diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> > index d5ccd46..4e095ae 100644
> > --- a/fs/cifs/cifsglob.h
> > +++ b/fs/cifs/cifsglob.h
> > @@ -548,7 +548,6 @@ struct cifsLockInfo {
> > š š š __u64 length;
> > š š š __u32 pid;
> > š š š __u8 type;
> > - š š __u16 netfid;
> > š};
> > 
> > š/*
> > @@ -573,6 +572,7 @@ struct cifs_search_info {
> > šstruct cifsFileInfo {
> > š š š struct list_head tlist; /* pointer to next fid owned by tcon */
> > š š š struct list_head flist; /* next fid (file instance) for this inode */
> > + š š struct list_head llist; /* brlocks held by this fid */
> 
> It would be nice to comment that the above list is intended to be
> protected by the lock_mutex (right?)
> 
> > š š š unsigned int uid; š š š /* allows finding which FileInfo structure */
> > š š š __u32 pid; š š š š š š š/* process id who opened file */
> > š š š __u16 netfid; š š š š š /* file id from remote */
> > @@ -613,7 +613,6 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
> > š */
> > 
> > šstruct cifsInodeInfo {
> > - š š struct list_head llist; š š š š /* brlocks for this inode */
> > š š š bool can_cache_brlcks;
> > š š š struct mutex lock_mutex; š š š š/* protect two fields above */
> > š š š /* BB add in lists for dirty pages i.e. write caching info for oplock */
> > diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> > index 2bf04e9..cc54033 100644
> > --- a/fs/cifs/file.c
> > +++ b/fs/cifs/file.c
> > @@ -264,6 +264,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
> > š š š pCifsFile->tlink = cifs_get_tlink(tlink);
> > š š š mutex_init(&pCifsFile->fh_mutex);
> > š š š INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
> > + š š INIT_LIST_HEAD(&pCifsFile->llist);
> > 
> > š š š spin_lock(&cifs_file_list_lock);
> > š š š list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
> > @@ -334,9 +335,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
> > š š š š* is closed anyway.
> > š š š š*/
> > š š š mutex_lock(&cifsi->lock_mutex);
> > - š š list_for_each_entry_safe(li, tmp, &cifsi->llist, llist) {
> > - š š š š š š if (li->netfid != cifs_file->netfid)
> > - š š š š š š š š š š continue;
> > + š š list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
> > š š š š š š š list_del(&li->llist);
> > š š š š š š š cifs_del_lock_waiters(li);
> > š š š š š š š kfree(li);
> > @@ -645,7 +644,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
> > š}
> > 
> > šstatic struct cifsLockInfo *
> > -cifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 netfid)
> > +cifs_lock_init(__u64 offset, __u64 length, __u8 type)
> > š{
> > š š š struct cifsLockInfo *lock =
> > š š š š š š š kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
> > @@ -654,7 +653,6 @@ cifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 \
> > netfid) š š š lock->offset = offset;
> > š š š lock->length = length;
> > š š š lock->type = type;
> > - š š lock->netfid = netfid;
> > š š š lock->pid = current->tgid;
> > š š š INIT_LIST_HEAD(&lock->blist);
> > š š š init_waitqueue_head(&lock->block_q);
> > @@ -687,19 +685,19 @@ cifs_locks_delete_block(struct file_lock *waiter)
> > š}
> > 
> > šstatic bool
> > -__cifs_find_lock_conflict(struct cifsInodeInfo *cinode, __u64 offset,
> > - š š š š š š š š š š __u64 length, __u8 type, __u16 netfid,
> > - š š š š š š š š š š struct cifsLockInfo **conf_lock)
> > +__cifs_find_fid_lock_conflict(struct cifsFileInfo *cfile, __u64 offset,
> > + š š š š š š š š š š š š š __u64 length, __u8 type, __u16 netfid,
> > + š š š š š š š š š š š š š struct cifsLockInfo **conf_lock)
> > š{
> > š š š struct cifsLockInfo *li, *tmp;
> > 
> > - š š list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
> > + š š list_for_each_entry_safe(li, tmp, &cfile->llist, llist) {
> 
> list_for_each_entry should be fine here since you're not doing
> gets/puts on these entries as you go.
> 
> > š š š š š š š if (offset + length <= li->offset ||
> > š š š š š š š š š offset >= li->offset + li->length)
> > š š š š š š š š š š š continue;
> > š š š š š š š else if ((type & LOCKING_ANDX_SHARED_LOCK) &&
> > - š š š š š š š š š š š((netfid == li->netfid && current->tgid == li->pid) ||
> > - š š š š š š š š š š š type == li->type))
> > + š š š š š š š š š š š((netfid == cfile->netfid && current->tgid == li->pid)
> > + š š š š š š š š š š š|| type == li->type))
> > š š š š š š š š š š š continue;
> > š š š š š š š else {
> > š š š š š š š š š š š *conf_lock = li;
> > @@ -710,11 +708,36 @@ __cifs_find_lock_conflict(struct cifsInodeInfo *cinode, \
> > __u64 offset, š}
> > 
> > šstatic bool
> > +__cifs_find_lock_conflict(struct cifsInodeInfo *cinode, __u64 offset,
> > + š š š š š š š š š š š __u64 length, __u8 type, __u16 netfid,
> > + š š š š š š š š š š š struct cifsLockInfo **conf_lock)
> > +{
> > + š š bool rc;
> > + š š struct cifsFileInfo *fid, *tmp;
> > +
> > + š š spin_lock(&cifs_file_list_lock);
> > + š š list_for_each_entry_safe(fid, tmp, &cinode->openFileList, flist) {
> > + š š š š š š cifsFileInfo_get(fid);
> > + š š š š š š spin_unlock(&cifs_file_list_lock);
> 
> NAK. list_for_each_entry_safe only protects you from removing the
> current entry of the list by preloading the next entry into "tmp". It's
> possible (even likely) that while this code is running, another thread
> could do the final cifsFileInfo_put on the entry that has already been
> preloaded into "tmp" and cause an oops or worse.

Yes, makes sense. Thanks!

> 
> > + š š š š š š rc = __cifs_find_fid_lock_conflict(fid, offset, length, type,
> > + š š š š š š š š š š š š š š š š š š š š š š š šnetfid, conf_lock);
> > + š š š š š š cifsFileInfo_put(fid);
> > + š š š š š š if (rc)
> > + š š š š š š š š š š return rc;
> > + š š š š š š spin_lock(&cifs_file_list_lock);
> > + š š }
> > + š š spin_unlock(&cifs_file_list_lock);
> > +
> > + š š return false;
> > +}
> > +
> > +static bool
> > šcifs_find_lock_conflict(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock,
> > - š š š š š š š š š š struct cifsLockInfo **conf_lock)
> > + š š š š š š š š š š __u16 netfid, struct cifsLockInfo **conf_lock)
> 
> Do we really need this wrapper? There's only one caller of
> cifs_find_lock_conflict, AFAICT.

This makes a caller code smarter, I think.

> 
> > š{
> > +
> > š š š return __cifs_find_lock_conflict(cinode, lock->offset, lock->length,
> > - š š š š š š š š š š š š š š š š š š šlock->type, lock->netfid, conf_lock);
> > + š š š š š š š š š š š š š š š š š š šlock->type, netfid, conf_lock);
> > š}
> > 
> > š/*
> > @@ -725,17 +748,18 @@ cifs_find_lock_conflict(struct cifsInodeInfo *cinode, \
> > struct cifsLockInfo *lock, š * the server or 1 otherwise.
> > š */
> > šstatic int
> > -cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length,
> > - š š š š š š__u8 type, __u16 netfid, struct file_lock *flock)
> > +cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
> > + š š š š š š__u8 type, struct file_lock *flock)
> > š{
> > š š š int rc = 0;
> > š š š struct cifsLockInfo *conf_lock;
> > + š š struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
> > š š š bool exist;
> > 
> > š š š mutex_lock(&cinode->lock_mutex);
> > 
> > - š š exist = __cifs_find_lock_conflict(cinode, offset, length, type, netfid,
> > - š š š š š š š š š š š š š š š š š š š &conf_lock);
> > + š š exist = __cifs_find_lock_conflict(cinode, offset, length, type,
> > + š š š š š š š š š š š š š š š š š š š cfile->netfid, &conf_lock);
> > š š š if (exist) {
> > š š š š š š š flock->fl_start = conf_lock->offset;
> > š š š š š š š flock->fl_end = conf_lock->offset + conf_lock->length - 1;
> > @@ -754,10 +778,11 @@ cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, \
> > __u64 length, š}
> > 
> > šstatic void
> > -cifs_lock_add(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock)
> > +cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock)
> > š{
> > + š š struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
> > š š š mutex_lock(&cinode->lock_mutex);
> > - š š list_add_tail(&lock->llist, &cinode->llist);
> > + š š list_add_tail(&lock->llist, &cfile->llist);
> > š š š mutex_unlock(&cinode->lock_mutex);
> > š}
> > 
> > @@ -768,10 +793,11 @@ cifs_lock_add(struct cifsInodeInfo *cinode, struct \
> > cifsLockInfo *lock) š * 3) -EACCESS, if there is a lock that prevents us and wait \
> > is false. š */
> > šstatic int
> > -cifs_lock_add_if(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock,
> > +cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock,
> > š š š š š š š šbool wait)
> > š{
> > š š š struct cifsLockInfo *conf_lock;
> > + š š struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
> > š š š bool exist;
> > š š š int rc = 0;
> > 
> > @@ -779,9 +805,10 @@ try_again:
> > š š š exist = false;
> > š š š mutex_lock(&cinode->lock_mutex);
> > 
> > - š š exist = cifs_find_lock_conflict(cinode, lock, &conf_lock);
> > + š š exist = cifs_find_lock_conflict(cinode, lock, cfile->netfid,
> > + š š š š š š š š š š š š š š š š š š &conf_lock);
> > š š š if (!exist && cinode->can_cache_brlcks) {
> > - š š š š š š list_add_tail(&lock->llist, &cinode->llist);
> > + š š š š š š list_add_tail(&lock->llist, &cfile->llist);
> > š š š š š š š mutex_unlock(&cinode->lock_mutex);
> > š š š š š š š return rc;
> > š š š }
> > @@ -928,7 +955,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
> > š š š for (i = 0; i < 2; i++) {
> > š š š š š š š cur = buf;
> > š š š š š š š num = 0;
> > - š š š š š š list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
> > + š š š š š š list_for_each_entry_safe(li, tmp, &cfile->llist, llist) {
> > š š š š š š š š š š š if (li->type != types[i])
> > š š š š š š š š š š š š š š š continue;
> > š š š š š š š š š š š cur->Pid = cpu_to_le16(li->pid);
> > @@ -1144,7 +1171,6 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 \
> > type, š š š __u64 length = 1 + flock->fl_end - flock->fl_start;
> > š š š struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
> > š š š struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
> > - š š struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
> > š š š __u16 netfid = cfile->netfid;
> > 
> > š š š if (posix_lck) {
> > @@ -1164,8 +1190,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 \
> > type, š š š š š š š return rc;
> > š š š }
> > 
> > - š š rc = cifs_lock_test(cinode, flock->fl_start, length, type, netfid,
> > - š š š š š š š š š š š š flock);
> > + š š rc = cifs_lock_test(cfile, flock->fl_start, length, type, flock);
> > š š š if (!rc)
> > š š š š š š š return rc;
> > 
> > @@ -1252,15 +1277,13 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct \
> > file_lock *flock, int xid) š š š for (i = 0; i < 2; i++) {
> > š š š š š š š cur = buf;
> > š š š š š š š num = 0;
> > - š š š š š š list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
> > + š š š š š š list_for_each_entry_safe(li, tmp, &cfile->llist, llist) {
> > š š š š š š š š š š š if (flock->fl_start > li->offset ||
> > š š š š š š š š š š š š š (flock->fl_start + length) <
> > š š š š š š š š š š š š š (li->offset + li->length))
> > š š š š š š š š š š š š š š š continue;
> > š š š š š š š š š š š if (current->tgid != li->pid)
> > š š š š š š š š š š š š š š š continue;
> > - š š š š š š š š š š if (cfile->netfid != li->netfid)
> > - š š š š š š š š š š š š š š continue;
> > š š š š š š š š š š š if (types[i] != li->type)
> > š š š š š š š š š š š š š š š continue;
> > š š š š š š š š š š š if (!cinode->can_cache_brlcks) {
> > @@ -1273,7 +1296,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct \
> > file_lock *flock, int xid) š š š š š š š š š š š š š š š š š š š \
> > cpu_to_le32((u32)(li->offset>>32)); š š š š š š š š š š š š š š š /*
> > š š š š š š š š š š š š š š š š* We need to save a lock here to let us add
> > - š š š š š š š š š š š š š š š* it again to the inode list if the unlock
> > + š š š š š š š š š š š š š š š* it again to the file's list if the unlock
> > š š š š š š š š š š š š š š š š* range request fails on the server.
> > š š š š š š š š š š š š š š š š*/
> > š š š š š š š š š š š š š š š list_move(&li->llist, &tmp_llist);
> > @@ -1287,10 +1310,10 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct \
> > file_lock *flock, int xid) š š š š š š š š š š š š š š š š š š š š š š š š* We \
> > failed on the unlock range š š š š š š š š š š š š š š š š š š š š š š š š* \
> > request - add all locks from š š š š š š š š š š š š š š š š š š š š š š š š* the \
> >                 tmp list to the head of
> > - š š š š š š š š š š š š š š š š š š š š š š š* the inode list.
> > + š š š š š š š š š š š š š š š š š š š š š š š* the file's list.
> > š š š š š š š š š š š š š š š š š š š š š š š š*/
> > š š š š š š š š š š š š š š š š š š š š š š š cifs_move_llist(&tmp_llist,
> > - š š š š š š š š š š š š š š š š š š š š š š š š š š š š š š &cinode->llist);
> > + š š š š š š š š š š š š š š š š š š š š š š š š š š š š š š &cfile->llist);
> > š š š š š š š š š š š š š š š š š š š š š š š rc = stored_rc;
> > š š š š š š š š š š š š š š š š š š š } else
> > š š š š š š š š š š š š š š š š š š š š š š š /*
> > @@ -1305,7 +1328,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct \
> > file_lock *flock, int xid) š š š š š š š š š š š } else {
> > š š š š š š š š š š š š š š š /*
> > š š š š š š š š š š š š š š š š* We can cache brlock requests - simply remove
> > - š š š š š š š š š š š š š š š* a lock from the inode list.
> > + š š š š š š š š š š š š š š š* a lock from the file's list.
> > š š š š š š š š š š š š š š š š*/
> > š š š š š š š š š š š š š š š list_del(&li->llist);
> > š š š š š š š š š š š š š š š cifs_del_lock_waiters(li);
> > @@ -1316,7 +1339,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct \
> > file_lock *flock, int xid) š š š š š š š š š š š stored_rc = cifs_lockv(xid, \
> > tcon, cfile->netfid, š š š š š š š š š š š š š š š š š š š š š š štypes[i], num, \
> > 0, buf); š š š š š š š š š š š if (stored_rc) {
> > - š š š š š š š š š š š š š š cifs_move_llist(&tmp_llist, &cinode->llist);
> > + š š š š š š š š š š š š š š cifs_move_llist(&tmp_llist, &cfile->llist);
> > š š š š š š š š š š š š š š š rc = stored_rc;
> > š š š š š š š š š š š } else
> > š š š š š š š š š š š š š š š cifs_free_llist(&tmp_llist);
> > @@ -1336,7 +1359,6 @@ cifs_setlk(struct file *file, šstruct file_lock *flock, \
> > __u8 type, š š š __u64 length = 1 + flock->fl_end - flock->fl_start;
> > š š š struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
> > š š š struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
> > - š š struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode);
> > š š š __u16 netfid = cfile->netfid;
> > 
> > š š š if (posix_lck) {
> > @@ -1363,11 +1385,11 @@ cifs_setlk(struct file *file, šstruct file_lock *flock, \
> > __u8 type, š š š if (lock) {
> > š š š š š š š struct cifsLockInfo *lock;
> > 
> > - š š š š š š lock = cifs_lock_init(flock->fl_start, length, type, netfid);
> > + š š š š š š lock = cifs_lock_init(flock->fl_start, length, type);
> > š š š š š š š if (!lock)
> > š š š š š š š š š š š return -ENOMEM;
> > 
> > - š š š š š š rc = cifs_lock_add_if(cinode, lock, wait_flag);
> > + š š š š š š rc = cifs_lock_add_if(cfile, lock, wait_flag);
> > š š š š š š š if (rc < 0)
> > š š š š š š š š š š š kfree(lock);
> > š š š š š š š if (rc <= 0)
> > @@ -1380,7 +1402,7 @@ cifs_setlk(struct file *file, šstruct file_lock *flock, \
> > __u8 type, š š š š š š š š š š š goto out;
> > š š š š š š š }
> > 
> > - š š š š š š cifs_lock_add(cinode, lock);
> > + š š š š š š cifs_lock_add(cfile, lock);
> > š š š } else if (unlock)
> > š š š š š š š rc = cifs_unlock_range(cfile, flock, xid);
> > 
> 
> 
> --
> Jeff Layton <jlayton@redhat.com>



-- 
Best regards,
Pavel Shilovsky.
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic