Re: [libvirt] PATCH: Add NUMA apis to remote driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, May 20, 2008 at 02:18:37PM +0200, Jim Meyering wrote:
> "Daniel P. Berrange" <berrange@xxxxxxxxxx> wrote:
> > On Tue, May 20, 2008 at 01:49:08PM +0200, Jim Meyering wrote:
> >>
> >> Looks fine.  Though you'll want to undo the global
> >> re-indentation-with-TABs in qemud/remote_protocol.h:
> >> Even ignoring all of the lines where 8-spaces -> TAB,
> >> there are a few new TABs:
> >
> > This is an autogenerated file. I mistakenly only fixed generation of the
> > C file and not the header. I'll redo the generation & fixup.
> 
> Oh!  That's what I thought at first, but when I found
> no rule for it in the Makefile.am, I presumed it was not.
> Should have known better.  It's just generated as a side-effect
> of generating the .c file.  Which means we can remove the .h
> file and it won't be regenerated.  We should correct that, eventually.

Its already correct AFAICT - the (simplified) rules we have in
qemud/Makefile.am are:

.x.c:
        rm -f $@
        rpcgen -c -o $@ $<
.x.h:
        rm -f $@
        rpcgen -h -o $@ $<

I merely needed to add a post procesing section to the latter

if GLIBC_RPCGEN
        mv $@ $@.bak
        sed -e 's/\t/        /g' $@.bak > $@
endif

to kill the tabs it inserts.

Revised patch follows...


 qemud/Makefile.am                   |    4 ++
 qemud/remote.c                      |   47 ++++++++++++++++++++++++++++++
 qemud/remote_dispatch_localvars.h   |    3 +
 qemud/remote_dispatch_proc_switch.h |   15 +++++++++
 qemud/remote_dispatch_prototypes.h  |    2 +
 qemud/remote_generate_stubs.pl      |   20 ++++++-------
 qemud/remote_protocol.c             |   30 +++++++++++++++++++
 qemud/remote_protocol.h             |   28 ++++++++++++++++++
 qemud/remote_protocol.x             |   21 +++++++++++++
 qemud/rpcgen_fix.pl                 |    4 +-
 src/remote_internal.c               |   55 +++++++++++++++++++++++++++++++++++-
 11 files changed, 216 insertions(+), 13 deletions(-)

Dan.


diff -r 261f28ba431e qemud/Makefile.am
--- a/qemud/Makefile.am	Fri May 16 16:09:50 2008 -0400
+++ b/qemud/Makefile.am	Tue May 20 10:49:20 2008 -0400
@@ -26,6 +26,10 @@
 .x.h:
 	rm -f $@
 	rpcgen -h -o $@ $<
+if GLIBC_RPCGEN
+	mv $@ $@.bak
+	sed -e 's/\t/        /g' $@.bak > $@
+endif
 endif
 
 remote_protocol.c: remote_protocol.h
diff -r 261f28ba431e qemud/remote.c
--- a/qemud/remote.c	Fri May 16 16:09:50 2008 -0400
+++ b/qemud/remote.c	Tue May 20 10:49:20 2008 -0400
@@ -594,6 +594,53 @@
     ret->capabilities = caps;
     return 0;
 }
+
+static int
+remoteDispatchNodeGetCellsFreeMemory (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                      struct qemud_client *client,
+                                      remote_message_header *req,
+                                      remote_node_get_cells_free_memory_args *args,
+                                      remote_node_get_cells_free_memory_ret *ret)
+{
+    CHECK_CONN(client);
+
+    if (args->maxCells > REMOTE_NODE_MAX_CELLS) {
+        remoteDispatchError (client, req,
+                             "%s", _("maxCells > REMOTE_NODE_MAX_CELLS"));
+        return -2;
+    }
+
+    /* Allocate return buffer. */
+    ret->freeMems.freeMems_val = calloc (args->maxCells, sizeof (*(ret->freeMems.freeMems_val)));
+
+    ret->freeMems.freeMems_len = virNodeGetCellsFreeMemory(client->conn,
+                                                           (unsigned long long *)ret->freeMems.freeMems_val,
+                                                           args->startCell,
+                                                           args->maxCells);
+    if (ret->freeMems.freeMems_len == 0)
+        return -1;
+
+    return 0;
+}
+
+
+static int
+remoteDispatchNodeGetFreeMemory (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                 struct qemud_client *client,
+                                 remote_message_header *req,
+                                 void *args ATTRIBUTE_UNUSED,
+                                 remote_node_get_free_memory_ret *ret)
+{
+    unsigned long long freeMem;
+    CHECK_CONN(client);
+
+    freeMem = virNodeGetFreeMemory(client->conn);
+    if (freeMem == 0) return -1;
+
+    ret->freeMem = freeMem;
+    return 0;
+}
+
 
 static int
 remoteDispatchDomainGetSchedulerType (struct qemud_server *server ATTRIBUTE_UNUSED,
diff -r 261f28ba431e qemud/remote_dispatch_localvars.h
--- a/qemud/remote_dispatch_localvars.h	Fri May 16 16:09:50 2008 -0400
+++ b/qemud/remote_dispatch_localvars.h	Tue May 20 10:49:20 2008 -0400
@@ -98,6 +98,8 @@
 remote_domain_migrate_prepare_args lv_remote_domain_migrate_prepare_args;
 remote_domain_migrate_prepare_ret lv_remote_domain_migrate_prepare_ret;
 remote_domain_undefine_args lv_remote_domain_undefine_args;
+remote_node_get_cells_free_memory_args lv_remote_node_get_cells_free_memory_args;
+remote_node_get_cells_free_memory_ret lv_remote_node_get_cells_free_memory_ret;
 remote_domain_get_scheduler_type_args lv_remote_domain_get_scheduler_type_args;
 remote_domain_get_scheduler_type_ret lv_remote_domain_get_scheduler_type_ret;
 remote_get_version_ret lv_remote_get_version_ret;
@@ -122,6 +124,7 @@
 remote_domain_set_autostart_args lv_remote_domain_set_autostart_args;
 remote_storage_pool_get_autostart_args lv_remote_storage_pool_get_autostart_args;
 remote_storage_pool_get_autostart_ret lv_remote_storage_pool_get_autostart_ret;
+remote_node_get_free_memory_ret lv_remote_node_get_free_memory_ret;
 remote_storage_vol_get_path_args lv_remote_storage_vol_get_path_args;
 remote_storage_vol_get_path_ret lv_remote_storage_vol_get_path_ret;
 remote_domain_lookup_by_id_args lv_remote_domain_lookup_by_id_args;
diff -r 261f28ba431e qemud/remote_dispatch_proc_switch.h
--- a/qemud/remote_dispatch_proc_switch.h	Fri May 16 16:09:50 2008 -0400
+++ b/qemud/remote_dispatch_proc_switch.h	Tue May 20 10:49:20 2008 -0400
@@ -491,6 +491,21 @@
         args = (char *) &lv_remote_network_undefine_args;
         memset (&lv_remote_network_undefine_args, 0, sizeof lv_remote_network_undefine_args);
         break;
+case REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY:
+        fn = (dispatch_fn) remoteDispatchNodeGetCellsFreeMemory;
+        args_filter = (xdrproc_t) xdr_remote_node_get_cells_free_memory_args;
+        args = (char *) &lv_remote_node_get_cells_free_memory_args;
+        memset (&lv_remote_node_get_cells_free_memory_args, 0, sizeof lv_remote_node_get_cells_free_memory_args);
+        ret_filter = (xdrproc_t) xdr_remote_node_get_cells_free_memory_ret;
+        ret = (char *) &lv_remote_node_get_cells_free_memory_ret;
+        memset (&lv_remote_node_get_cells_free_memory_ret, 0, sizeof lv_remote_node_get_cells_free_memory_ret);
+        break;
+case REMOTE_PROC_NODE_GET_FREE_MEMORY:
+        fn = (dispatch_fn) remoteDispatchNodeGetFreeMemory;
+        ret_filter = (xdrproc_t) xdr_remote_node_get_free_memory_ret;
+        ret = (char *) &lv_remote_node_get_free_memory_ret;
+        memset (&lv_remote_node_get_free_memory_ret, 0, sizeof lv_remote_node_get_free_memory_ret);
+        break;
 case REMOTE_PROC_NODE_GET_INFO:
         fn = (dispatch_fn) remoteDispatchNodeGetInfo;
         ret_filter = (xdrproc_t) xdr_remote_node_get_info_ret;
diff -r 261f28ba431e qemud/remote_dispatch_prototypes.h
--- a/qemud/remote_dispatch_prototypes.h	Fri May 16 16:09:50 2008 -0400
+++ b/qemud/remote_dispatch_prototypes.h	Tue May 20 10:49:20 2008 -0400
@@ -67,6 +67,8 @@
 static int remoteDispatchNetworkLookupByUuid (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_lookup_by_uuid_args *args, remote_network_lookup_by_uuid_ret *ret);
 static int remoteDispatchNetworkSetAutostart (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_set_autostart_args *args, void *ret);
 static int remoteDispatchNetworkUndefine (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_undefine_args *args, void *ret);
+static int remoteDispatchNodeGetCellsFreeMemory (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_get_cells_free_memory_args *args, remote_node_get_cells_free_memory_ret *ret);
+static int remoteDispatchNodeGetFreeMemory (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_node_get_free_memory_ret *ret);
 static int remoteDispatchNodeGetInfo (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_node_get_info_ret *ret);
 static int remoteDispatchNumOfDefinedDomains (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_domains_ret *ret);
 static int remoteDispatchNumOfDefinedNetworks (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_networks_ret *ret);
diff -r 261f28ba431e qemud/remote_generate_stubs.pl
--- a/qemud/remote_generate_stubs.pl	Fri May 16 16:09:50 2008 -0400
+++ b/qemud/remote_generate_stubs.pl	Tue May 20 10:49:20 2008 -0400
@@ -84,8 +84,8 @@
     my @keys = sort (keys %calls);
     foreach (@keys) {
 	print "$_:\n";
-	print "\tname $calls{$_}->{name} ($calls{$_}->{ProcName})\n";
-	print "\t$calls{$_}->{args} -> $calls{$_}->{ret}\n";
+	print "        name $calls{$_}->{name} ($calls{$_}->{ProcName})\n";
+	print "        $calls{$_}->{args} -> $calls{$_}->{ret}\n";
     }
 }
 
@@ -117,18 +117,18 @@
     my @keys = sort (keys %calls);
     foreach (@keys) {
 	print "case REMOTE_PROC_$calls{$_}->{UC_NAME}:\n";
-	print "\tfn = (dispatch_fn) remoteDispatch$calls{$_}->{ProcName};\n";
+	print "        fn = (dispatch_fn) remoteDispatch$calls{$_}->{ProcName};\n";
 	if ($calls{$_}->{args} ne "void") {
-	    print "\targs_filter = (xdrproc_t) xdr_$calls{$_}->{args};\n";
-	    print "\targs = (char *) &lv_$calls{$_}->{args};\n";
-	    print "\tmemset (&lv_$calls{$_}->{args}, 0, sizeof lv_$calls{$_}->{args});\n"
+	    print "        args_filter = (xdrproc_t) xdr_$calls{$_}->{args};\n";
+	    print "        args = (char *) &lv_$calls{$_}->{args};\n";
+	    print "        memset (&lv_$calls{$_}->{args}, 0, sizeof lv_$calls{$_}->{args});\n"
 	}
 	if ($calls{$_}->{ret} ne "void") {
-	    print "\tret_filter = (xdrproc_t) xdr_$calls{$_}->{ret};\n";
-	    print "\tret = (char *) &lv_$calls{$_}->{ret};\n";
-	    print "\tmemset (&lv_$calls{$_}->{ret}, 0, sizeof lv_$calls{$_}->{ret});\n"
+	    print "        ret_filter = (xdrproc_t) xdr_$calls{$_}->{ret};\n";
+	    print "        ret = (char *) &lv_$calls{$_}->{ret};\n";
+	    print "        memset (&lv_$calls{$_}->{ret}, 0, sizeof lv_$calls{$_}->{ret});\n"
 	}
-	print "\tbreak;\n";
+	print "        break;\n";
     }
 }
 
diff -r 261f28ba431e qemud/remote_protocol.c
--- a/qemud/remote_protocol.c	Fri May 16 16:09:50 2008 -0400
+++ b/qemud/remote_protocol.c	Tue May 20 10:49:20 2008 -0400
@@ -382,6 +382,36 @@
 {
 
          if (!xdr_remote_nonnull_string (xdrs, &objp->capabilities))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_node_get_cells_free_memory_args (XDR *xdrs, remote_node_get_cells_free_memory_args *objp)
+{
+
+         if (!xdr_int (xdrs, &objp->startCell))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->maxCells))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_node_get_cells_free_memory_ret (XDR *xdrs, remote_node_get_cells_free_memory_ret *objp)
+{
+
+         if (!xdr_array (xdrs, (char **)&objp->freeMems.freeMems_val, (u_int *) &objp->freeMems.freeMems_len, REMOTE_NODE_MAX_CELLS,
+                sizeof (quad_t), (xdrproc_t) xdr_quad_t))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_node_get_free_memory_ret (XDR *xdrs, remote_node_get_free_memory_ret *objp)
+{
+
+         if (!xdr_quad_t (xdrs, &objp->freeMem))
                  return FALSE;
         return TRUE;
 }
diff -r 261f28ba431e qemud/remote_protocol.h
--- a/qemud/remote_protocol.h	Fri May 16 16:09:50 2008 -0400
+++ b/qemud/remote_protocol.h	Tue May 20 10:49:20 2008 -0400
@@ -30,6 +30,7 @@
 #define REMOTE_STORAGE_POOL_NAME_LIST_MAX 256
 #define REMOTE_STORAGE_VOL_NAME_LIST_MAX 1024
 #define REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX 16
+#define REMOTE_NODE_MAX_CELLS 1024
 #define REMOTE_AUTH_SASL_DATA_MAX 65536
 #define REMOTE_AUTH_TYPE_LIST_MAX 20
 
@@ -175,6 +176,25 @@
         remote_nonnull_string capabilities;
 };
 typedef struct remote_get_capabilities_ret remote_get_capabilities_ret;
+
+struct remote_node_get_cells_free_memory_args {
+        int startCell;
+        int maxCells;
+};
+typedef struct remote_node_get_cells_free_memory_args remote_node_get_cells_free_memory_args;
+
+struct remote_node_get_cells_free_memory_ret {
+        struct {
+                u_int freeMems_len;
+                quad_t *freeMems_val;
+        } freeMems;
+};
+typedef struct remote_node_get_cells_free_memory_ret remote_node_get_cells_free_memory_ret;
+
+struct remote_node_get_free_memory_ret {
+        quad_t freeMem;
+};
+typedef struct remote_node_get_free_memory_ret remote_node_get_free_memory_ret;
 
 struct remote_domain_get_scheduler_type_args {
         remote_nonnull_domain dom;
@@ -1116,6 +1136,8 @@
         REMOTE_PROC_STORAGE_VOL_GET_INFO = 98,
         REMOTE_PROC_STORAGE_VOL_DUMP_XML = 99,
         REMOTE_PROC_STORAGE_VOL_GET_PATH = 100,
+        REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101,
+        REMOTE_PROC_NODE_GET_FREE_MEMORY = 102,
 };
 typedef enum remote_procedure remote_procedure;
 
@@ -1172,6 +1194,9 @@
 extern  bool_t xdr_remote_get_max_vcpus_ret (XDR *, remote_get_max_vcpus_ret*);
 extern  bool_t xdr_remote_node_get_info_ret (XDR *, remote_node_get_info_ret*);
 extern  bool_t xdr_remote_get_capabilities_ret (XDR *, remote_get_capabilities_ret*);
+extern  bool_t xdr_remote_node_get_cells_free_memory_args (XDR *, remote_node_get_cells_free_memory_args*);
+extern  bool_t xdr_remote_node_get_cells_free_memory_ret (XDR *, remote_node_get_cells_free_memory_ret*);
+extern  bool_t xdr_remote_node_get_free_memory_ret (XDR *, remote_node_get_free_memory_ret*);
 extern  bool_t xdr_remote_domain_get_scheduler_type_args (XDR *, remote_domain_get_scheduler_type_args*);
 extern  bool_t xdr_remote_domain_get_scheduler_type_ret (XDR *, remote_domain_get_scheduler_type_ret*);
 extern  bool_t xdr_remote_domain_get_scheduler_parameters_args (XDR *, remote_domain_get_scheduler_parameters_args*);
@@ -1344,6 +1369,9 @@
 extern bool_t xdr_remote_get_max_vcpus_ret ();
 extern bool_t xdr_remote_node_get_info_ret ();
 extern bool_t xdr_remote_get_capabilities_ret ();
+extern bool_t xdr_remote_node_get_cells_free_memory_args ();
+extern bool_t xdr_remote_node_get_cells_free_memory_ret ();
+extern bool_t xdr_remote_node_get_free_memory_ret ();
 extern bool_t xdr_remote_domain_get_scheduler_type_args ();
 extern bool_t xdr_remote_domain_get_scheduler_type_ret ();
 extern bool_t xdr_remote_domain_get_scheduler_parameters_args ();
diff -r 261f28ba431e qemud/remote_protocol.x
--- a/qemud/remote_protocol.x	Fri May 16 16:09:50 2008 -0400
+++ b/qemud/remote_protocol.x	Tue May 20 10:49:20 2008 -0400
@@ -86,6 +86,9 @@
 
 /* Upper limit on list of scheduler parameters. */
 const REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX = 16;
+
+/* Upper limit on number of NUMA cells */
+const REMOTE_NODE_MAX_CELLS = 1024;
 
 /* Upper limit on SASL auth negotiation packet */
 const REMOTE_AUTH_SASL_DATA_MAX = 65536;
@@ -252,6 +255,19 @@
 
 struct remote_get_capabilities_ret {
     remote_nonnull_string capabilities;
+};
+
+struct remote_node_get_cells_free_memory_args {
+    int startCell;
+    int maxCells;
+};
+
+struct remote_node_get_cells_free_memory_ret {
+    hyper freeMems<REMOTE_NODE_MAX_CELLS>;
+};
+
+struct remote_node_get_free_memory_ret {
+    hyper freeMem;
 };
 
 struct remote_domain_get_scheduler_type_args {
@@ -1017,7 +1033,10 @@
     REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_PATH = 97,
     REMOTE_PROC_STORAGE_VOL_GET_INFO = 98,
     REMOTE_PROC_STORAGE_VOL_DUMP_XML = 99,
-    REMOTE_PROC_STORAGE_VOL_GET_PATH = 100
+    REMOTE_PROC_STORAGE_VOL_GET_PATH = 100,
+
+    REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101,
+    REMOTE_PROC_NODE_GET_FREE_MEMORY = 102
 };
 
 /* Custom RPC structure. */
diff -r 261f28ba431e qemud/rpcgen_fix.pl
--- a/qemud/rpcgen_fix.pl	Fri May 16 16:09:50 2008 -0400
+++ b/qemud/rpcgen_fix.pl	Tue May 20 10:49:20 2008 -0400
@@ -23,6 +23,8 @@
 	print;
 	next;
     }
+
+    s/\t/        /g;
 
     if (m/^}/) {
 	$in_function = 0;
@@ -52,7 +54,7 @@
 	    foreach (keys %uses) {
 		$i = $uses{$_};
 		unshift @function,
-		("\tchar **objp_cpp$i = (char **) (void *) &$_;\n");
+		("        char **objp_cpp$i = (char **) (void *) &$_;\n");
 		$i++;
 	    }
 	    @function =
diff -r 261f28ba431e src/remote_internal.c
--- a/src/remote_internal.c	Fri May 16 16:09:50 2008 -0400
+++ b/src/remote_internal.c	Tue May 20 10:49:20 2008 -0400
@@ -1327,6 +1327,58 @@
     /* Caller frees this. */
     return ret.capabilities;
 }
+
+static int
+remoteNodeGetCellsFreeMemory(virConnectPtr conn,
+                            unsigned long long *freeMems,
+                            int startCell,
+                            int maxCells)
+{
+    remote_node_get_cells_free_memory_args args;
+    remote_node_get_cells_free_memory_ret ret;
+    int i;
+    GET_PRIVATE (conn, -1);
+
+    if (maxCells > REMOTE_NODE_MAX_CELLS) {
+        errorf (conn, VIR_ERR_RPC,
+                _("too many NUMA cells: %d > %d"),
+                maxCells,
+                REMOTE_NODE_MAX_CELLS);
+        return -1;
+    }
+
+    args.startCell = startCell;
+    args.maxCells = maxCells;
+
+    memset (&ret, 0, sizeof ret);
+    if (call (conn, priv, 0, REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY,
+              (xdrproc_t) xdr_remote_node_get_cells_free_memory_args, (char *)&args,
+              (xdrproc_t) xdr_remote_node_get_cells_free_memory_ret, (char *)&ret) == -1)
+        return -1;
+
+    for (i = 0 ; i < ret.freeMems.freeMems_len ; i++)
+        freeMems[i] = ret.freeMems.freeMems_val[i];
+
+    xdr_free((xdrproc_t) xdr_remote_node_get_cells_free_memory_ret, (char *) &ret);
+
+    return ret.freeMems.freeMems_len;
+}
+
+static unsigned long long
+remoteNodeGetFreeMemory (virConnectPtr conn)
+{
+    remote_node_get_free_memory_ret ret;
+    GET_PRIVATE (conn, -1);
+
+    memset (&ret, 0, sizeof ret);
+    if (call (conn, priv, 0, REMOTE_PROC_NODE_GET_FREE_MEMORY,
+              (xdrproc_t) xdr_void, NULL,
+              (xdrproc_t) xdr_remote_node_get_free_memory_ret, (char *)&ret) == -1)
+        return 0;
+
+    return ret.freeMem;
+}
+
 
 static int
 remoteListDomains (virConnectPtr conn, int *ids, int maxids)
@@ -4728,7 +4780,8 @@
     .domainMigrateFinish = remoteDomainMigrateFinish,
     .domainBlockStats = remoteDomainBlockStats,
     .domainInterfaceStats = remoteDomainInterfaceStats,
-    .nodeGetCellsFreeMemory = NULL,
+    .nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory,
+    .getFreeMemory = remoteNodeGetFreeMemory,
 };
 
 static virNetworkDriver network_driver = {



-- 
|: Red Hat, Engineering, Boston   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

--
Libvir-list mailing list
Libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list

[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]