2010-06-22 15:45:11

by Suresh Jayaraman

[permalink] [raw]
Subject: [RFC][PATCH 05/10] cifs: define superblock-level cache index objects and register them

Define superblock-level cache index objects (managed by cifsTconInfo structs).
Each superblock object is created in a server-level index object and in itself
an index into which inode-level objects are inserted.

Currently, the superblock objects are keyed by sharename.

Signed-off-by: Suresh Jayaraman <[email protected]>
---
fs/cifs/cache.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/cifsglob.h | 3 ++
fs/cifs/connect.c | 4 +++
fs/cifs/fscache.c | 17 ++++++++++++++
fs/cifs/fscache.h | 6 +++++
5 files changed, 92 insertions(+)

Index: cifs-2.6/fs/cifs/cache.c
===================================================================
--- cifs-2.6.orig/fs/cifs/cache.c
+++ cifs-2.6/fs/cifs/cache.c
@@ -76,3 +76,65 @@ const struct fscache_cookie_def cifs_fsc
.type = FSCACHE_COOKIE_TYPE_INDEX,
.get_key = cifs_server_get_key,
};
+
+static char *extract_sharename(const char *treename)
+{
+ const char *src;
+ char *delim, *dst;
+ int len;
+
+ /* skip double chars at the beginning */
+ src = treename + 2;
+
+ /* share name is always preceded by '\\' now */
+ delim = strchr(src, '\\');
+ if (!delim)
+ return ERR_PTR(-EINVAL);
+ delim++;
+ len = strlen(delim);
+
+ /* caller has to free the memory */
+ dst = kstrndup(delim, len, GFP_KERNEL);
+ if (!dst)
+ return ERR_PTR(-ENOMEM);
+
+ return dst;
+}
+
+/*
+ * Superblock object currently keyed by share name
+ */
+static uint16_t cifs_super_get_key(const void *cookie_netfs_data, void *buffer,
+ uint16_t maxbuf)
+{
+ const struct cifsTconInfo *tcon = cookie_netfs_data;
+ char *sharename;
+ uint16_t len;
+
+ sharename = extract_sharename(tcon->treeName);
+ if (IS_ERR(sharename)) {
+ cFYI(1, "CIFS: couldn't extract sharename\n");
+ sharename = NULL;
+ return 0;
+ }
+
+ len = strlen(sharename);
+ if (len > maxbuf)
+ return 0;
+
+ memcpy(buffer, sharename, len);
+
+ kfree(sharename);
+
+ return len;
+}
+
+/*
+ * Superblock object for FS-Cache
+ */
+const struct fscache_cookie_def cifs_fscache_super_index_def = {
+ .name = "CIFS.super",
+ .type = FSCACHE_COOKIE_TYPE_INDEX,
+ .get_key = cifs_super_get_key,
+};
+
Index: cifs-2.6/fs/cifs/cifsglob.h
===================================================================
--- cifs-2.6.orig/fs/cifs/cifsglob.h
+++ cifs-2.6/fs/cifs/cifsglob.h
@@ -317,6 +317,9 @@ struct cifsTconInfo {
bool local_lease:1; /* check leases (only) on local system not remote */
bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
bool need_reconnect:1; /* connection reset, tid now invalid */
+#ifdef CONFIG_CIFS_FSCACHE
+ struct fscache_cookie *fscache; /* cookie for share */
+#endif
/* BB add field for back pointer to sb struct(s)? */
};

Index: cifs-2.6/fs/cifs/connect.c
===================================================================
--- cifs-2.6.orig/fs/cifs/connect.c
+++ cifs-2.6/fs/cifs/connect.c
@@ -1773,6 +1773,8 @@ cifs_put_tcon(struct cifsTconInfo *tcon)
list_del_init(&tcon->tcon_list);
write_unlock(&cifs_tcp_ses_lock);

+ cifs_fscache_release_super_cookie(tcon);
+
xid = GetXid();
CIFSSMBTDis(xid, tcon);
_FreeXid(xid);
@@ -1843,6 +1845,8 @@ cifs_get_tcon(struct cifsSesInfo *ses, s
tcon->nocase = volume_info->nocase;
tcon->local_lease = volume_info->local_lease;

+ cifs_fscache_get_super_cookie(tcon);
+
write_lock(&cifs_tcp_ses_lock);
list_add(&tcon->tcon_list, &ses->tcon_list);
write_unlock(&cifs_tcp_ses_lock);
Index: cifs-2.6/fs/cifs/fscache.c
===================================================================
--- cifs-2.6.orig/fs/cifs/fscache.c
+++ cifs-2.6/fs/cifs/fscache.c
@@ -45,3 +45,20 @@ void cifs_fscache_release_client_cookie(
server->fscache = NULL;
}

+void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon)
+{
+ tcon->fscache =
+ fscache_acquire_cookie(tcon->ses->server->fscache,
+ &cifs_fscache_super_index_def, tcon);
+ cFYI(1, "CIFS: get superblock cookie (0x%p/0x%p)\n",
+ tcon, tcon->fscache);
+}
+
+void cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon)
+{
+ cFYI(1, "CIFS: releasing superblock cookie (0x%p/0x%p)\n",
+ tcon, tcon->fscache);
+ fscache_relinquish_cookie(tcon->fscache, 0);
+ tcon->fscache = NULL;
+}
+
Index: cifs-2.6/fs/cifs/fscache.h
===================================================================
--- cifs-2.6.orig/fs/cifs/fscache.h
+++ cifs-2.6/fs/cifs/fscache.h
@@ -28,6 +28,7 @@

extern struct fscache_netfs cifs_fscache_netfs;
extern const struct fscache_cookie_def cifs_fscache_server_index_def;
+extern const struct fscache_cookie_def cifs_fscache_super_index_def;

extern int cifs_fscache_register(void);
extern void cifs_fscache_unregister(void);
@@ -37,6 +38,8 @@ extern void cifs_fscache_unregister(void
*/
extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *);
extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *);
+extern void cifs_fscache_get_super_cookie(struct cifsTconInfo *);
+extern void cifs_fscache_release_super_cookie(struct cifsTconInfo *);

#else /* CONFIG_CIFS_FSCACHE */
static inline int cifs_fscache_register(void) { return 0; }
@@ -46,6 +49,9 @@ static inline void
cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {}
static inline void
cifs_fscache_get_client_cookie(struct TCP_Server_Info *server); {}
+static inline void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon) {}
+static inline void
+cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon) {}

#endif /* CONFIG_CIFS_FSCACHE */


2010-06-23 16:58:18

by David Howells

[permalink] [raw]
Subject: Re: [RFC][PATCH 05/10] cifs: define superblock-level cache index objects and register them

Suresh Jayaraman <[email protected]> wrote:

> Define superblock-level cache index objects (managed by cifsTconInfo
> structs). Each superblock object is created in a server-level index object
> and in itself an index into which inode-level objects are inserted.
>
> Currently, the superblock objects are keyed by sharename.

Seems reasonable. Is there any way you can check that the share you are
looking at on a server is the same as the last time you looked? Can you
validate the root directory of the share in some way?

David

2010-06-25 12:44:27

by Suresh Jayaraman

[permalink] [raw]
Subject: Re: [RFC][PATCH 05/10] cifs: define superblock-level cache index objects and register them

On 06/23/2010 10:28 PM, David Howells wrote:
> Suresh Jayaraman <[email protected]> wrote:
>
>> Define superblock-level cache index objects (managed by cifsTconInfo
>> structs). Each superblock object is created in a server-level index object
>> and in itself an index into which inode-level objects are inserted.
>>
>> Currently, the superblock objects are keyed by sharename.
>
> Seems reasonable. Is there any way you can check that the share you are
> looking at on a server is the same as the last time you looked? Can you

Good point.

I thought of using TID (Tree identifier; a unique ID for a resource in
use by client) along with sharename. But, Server is free to reuse them
when the tree connection closes and does not guarantee the same Tid for
a particular resource across tree connections.

Also, considering the UNC name of the resource (//server/share) may not
be a good idea too as the cache will not be used when for e.g. IPaddress
is used to mount.

So, if a server does something like this:
- export a share 'foo' (original server path: /export/vol1/foo)
- client mounts and uses it
- server unexports the share 'foo'
- server exports 'foo' (original sever path: /export/vol2/foo)

we have a bit of problem..

> validate the root directory of the share in some way?
>

I don't know if there is a way to do this.

Thanks,


--
Suresh Jayaraman

2010-06-25 12:58:41

by David Howells

[permalink] [raw]
Subject: Re: [RFC][PATCH 05/10] cifs: define superblock-level cache index objects and register them

Suresh Jayaraman <[email protected]> wrote:

> Also, considering the UNC name of the resource (//server/share) may not
> be a good idea too as the cache will not be used when for e.g. IPaddress
> is used to mount.

You could convert the UNC name to an IP address, and just use that as your
key.

> > validate the root directory of the share in some way?
>
> I don't know if there is a way to do this.

Is there an inode number or something? Even the creation time might do.

David

2010-06-25 13:27:04

by David Howells

[permalink] [raw]
Subject: Re: [RFC][PATCH 05/10] cifs: define superblock-level cache index objects and register them

David Howells <[email protected]> wrote:

> > > validate the root directory of the share in some way?
> >
> > I don't know if there is a way to do this.
>
> Is there an inode number or something? Even the creation time might do.

Looking in cifspdu.h, there are a number of things that it might be possible
to use.

(1) FILE_ALL_INFO: CreationTime, IndexNumber, IndexNumber1, FileName
(assuming this isn't flattened to '\' or something for the root of a
share.

(2) FILE_UNIX_BASIC_INFO: DevMajor, DevMinor, UniqueId.

(3) FILE_INFO_STANDARD: CreationDate, CreationTime.

(4) FILE_INFO_BASIC: CreationTime.

(5) FILE_DIRECTORY_INFO: FileIndex, CreationTime, FileName.

(6) SEARCH_ID_FULL_DIR_INFO: FileIndex, CreationTime, UniqueId, FileName.

(7) FILE_BOTH_DIRECTORY_INFO: FileIndex, CreationTime, ShortName, FileName.

(8) OPEN_RSP_EXT: Fid, CreationTime, VolumeGUID, FileId.

You may have to choose different sets of things, depending on what the server
has on offer. Also, don't forget, if you can't work out whether a share is
coherent or not from the above, you can always use LastWriteTime, ChangeTime
and EndOfFile and just discard the whole subtree if they differ.

David

2010-06-28 12:53:25

by Suresh Jayaraman

[permalink] [raw]
Subject: Re: [RFC][PATCH 05/10] cifs: define superblock-level cache index objects and register them

On 06/25/2010 06:56 PM, David Howells wrote:
> David Howells <[email protected]> wrote:
>
>>>> validate the root directory of the share in some way?
>>>
>>> I don't know if there is a way to do this.
>>
>> Is there an inode number or something? Even the creation time might do.
>
> Looking in cifspdu.h, there are a number of things that it might be possible
> to use.
>
> (1) FILE_ALL_INFO: CreationTime, IndexNumber, IndexNumber1, FileName
> (assuming this isn't flattened to '\' or something for the root of a
> share.
>
> (2) FILE_UNIX_BASIC_INFO: DevMajor, DevMinor, UniqueId.
>
> (3) FILE_INFO_STANDARD: CreationDate, CreationTime.
>
> (4) FILE_INFO_BASIC: CreationTime.
>
> (5) FILE_DIRECTORY_INFO: FileIndex, CreationTime, FileName.
>
> (6) SEARCH_ID_FULL_DIR_INFO: FileIndex, CreationTime, UniqueId, FileName.
>
> (7) FILE_BOTH_DIRECTORY_INFO: FileIndex, CreationTime, ShortName, FileName.
>
> (8) OPEN_RSP_EXT: Fid, CreationTime, VolumeGUID, FileId.
>
> You may have to choose different sets of things, depending on what the server
> has on offer. Also, don't forget, if you can't work out whether a share is

Did you mean we need to validate differently for different servers?

I just did some testing and it looks like we could rely on CreationTime,
IndexNumber for validating with Windows servers (FileName is relative to
the mapped drive) and UniqueId for validating with Samba servers. I did
not test all possibilities (there could be more).

> coherent or not from the above, you can always use LastWriteTime, ChangeTime
> and EndOfFile and just discard the whole subtree if they differ.
>

Thanks,

--
Suresh Jayaraman

2010-06-28 13:24:57

by David Howells

[permalink] [raw]
Subject: Re: [RFC][PATCH 05/10] cifs: define superblock-level cache index objects and register them

Suresh Jayaraman <[email protected]> wrote:

> Did you mean we need to validate differently for different servers?

You may need to, yes, as different servers may make different attributes
available.

This isn't too bad. Each server index record in the cache has freeform
auxiliary data, just as does each file data record. You could, say, stick a
byte at the front that indicates what you've stored in there.

David